在80个JVM集群中寻猎内存泄漏OOM

你是否经常启动JVM以避免内存泄漏OOM(out of memory),或者接受专家的意见,只增加Java堆空间?

下面这张内存表显示在8台集群机器上每台10个JVM的内存消耗(每个Heap堆是4.1GB),它是为在线购物旺季准备的大型网上零售商店,却因为OOM错误使得主机崩溃。

应用团队“解决”这个问题的第一个响应是给这些主机添加更多的内存。由于这个过程太长,促使我们决定把眼光放在寻求详尽的内存消耗的实际根源上。

每当JVM的崩溃,它的APM解决方案是,积极捕捉一个完整的堆内存。这使得分析哪些类过多占用内存变得非常方便的。在这种情况下是容易辨认热点问题。下面的截图显示,根源是22.7k T4CStatement对象。他们消耗了约2.6GB堆内存,他们没有被垃圾收集器清除的原因是因为他们是在全局静态变量被引用:

分配这些T4CStatement对象是一个SQL语句通过allocateStatement方法调用的createStatement执行和被分配的。用这种方法的问题是,T4CStatement对象被分配后永远不会被释放,相关的连接被放入到连接池了:

大部分这些对象已经在堆上占据几个小时甚至几天的时间没有释放:

问题解决:
Oracle的JDBC驱动程序存在BUG, 它在一个全局变量中保存这些对象,因而不能被GC清理。联系他们后修复。