自己最近做了一些关于工厂MES软件导致的OOM,比如avon,andersen,ford, 这是给公司同事做的OutOfMemory定位问题的分享,垃圾回收是参考江南白衣的一篇博文,各个点都是些比较表层的sharing,还没有写完,也和广大同仁做个交流
1 分析工具
1) 动态分析工具
Jprofile
2) 静态分析工具
a: 在启动java的时候加上参数 -XX:+HeapDumpOnOutOfMemoryError,这样如果由于OOM导致JVM crash的时候可以便于我们分析,生成的heap dump文件名字的命名规范如下, java_pidxxxx.hprof
b: 工具1 elcipsemat
2 IBM heap ana java -Xmx1600 -jar ha396.jar
2 Java 内存机制和Exception实例
1对于从事C、C++程序开发的开发人员来说,担负着每一个对象生命开始到终结的维护责任。
对于Java程序员来说,不需要在为每一个new操作去写配对的delete/free,不容易出现内容泄漏和内存溢出错误。不过,也正是因为Java程序员把内存控制的权力交给了JVM,一旦出现泄漏和溢出,如果不了解JVM是怎样使用内存的,那排查错误将会是一件非常困难的事情。下面介绍一下java出现的OOM有关的 Exception和可能出现的方式
A Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
public static void main(String[] args) {
//使用List保持着常量池引用,压制Full GC回收常量池行为
List<String> list = new ArrayList<String>();
// 10M的PermSize在integer范围内足够产生OOM了
int i = 0;
while (true) {
list.add(String.valueOf(i++).intern());
}
}
这一部分用于存放Class和Meta的信息,Class在被 Load的时候被放入PermGen space区域(包括常量池: 静态变量),它和和存放Instance的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGen space错误动态生成的类,加载如Spring、Hibernate对类进行增强时,都会使用到CGLib这类字节码技术,当增强的类越多,就需要越大的方法区用于保证动态生成的Class可以加载入内存。
B java.lang.OutOfMemoryError: Java heap space,被缓存的实例(Cache)对象,大的map,list引用大的对象等等,都会保存于此
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
int i = 0;
while (true) {
list.add(new String(“test”));
}
}
C Exception in thread "main" java.lang.StackOverflowError
栈帧太多,也就是函数调用层级过多)导致。检查是否有死递归的情况~
/**
* VM Args:-Xss128k
*/
public class JavaVMStackSOF {
private int stackLength = 1;
public void stackLeak() {
stackLength++;
stackLeak();
}
public static void main(String[] args) throws Throwable {
JavaVMStackSOF oom = new JavaVMStackSOF();
try {
oom.stackLeak();
} catch (Throwable e) {
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}
2 Java 垃圾回收机制
基本回收算法
分代垃圾回收详述
如上图所示,为Java堆中的各代分布。
3实战演练
背景介绍
1这个是Andersen window 的一个Support Case,他们用我们FTPC的Form开发了一个从ERP系统导入WorkOrder等到我们FTPC系统的一个转换程序,他们把ERP系统的所有Order写到一个txt文件里面,然后用他们的写的应用来转换txt中的Order信息到我们FTPC的Lot, workorder对象等等。但是他们发现有个问题,就是导入的txt文件如果过大的话,就会有可能报出OOM异常,这个对他们影响是很大的,他们不知道当前导入了多少order,没法回滚脏数据。于是Support建议他们加大Client端的内存,但是这样还是会有问题的,因为你不知道从ERP导出的txt的文件有多大。
2
这里可以让大家猜测大概是什么问题导致的内存泄露
这个是用 IBM heap ana分析的视图,大家可以看一下,有96%内存都在pnuts/lang/context中,其中92%内存是被lot对象占用的,lot对象保存到Vector中,所以是由于lot对象保存在Vector中,但是vector没有及时释放这些对象导致的。
3实际内存泄露的代码.
Please locate the lines of code around line 2736 of Subroutine ImportWoFile. Following is the some pieces of the codes about it:
foreach orderItem(vecOrderItems.elements())
{
….
newLot = createLot(strLotName, workOrder)
…
newLot.save()
…
if (blnSaveOK == false)
{
……
} else
{
//vectLot is a Vector collection customer defined newly on 10/10/2010
vecLot.addElement(newLot)
….
}
}
My conclusion:Obviously, the lot of vectLot will be tremendous if they want to import a large wo file at one time. So it will consume the memory of JVM.