《深入理解java虚拟机》读书笔记二 【OutOfMemoryError】

时间:2021-09-08 11:42:23

1. java堆溢出

EclipseIDE设置:debugconfiguration-->javaapplication-->class-->VMArguments

-Xms20M -Xmx20M -Xmn10M 

-XX:+PrintGCDetails

/**
* VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
*
*/
public class HeapOOM {
static class OOMObject{

}
public static void main(String[] args){
List<OOMObject> list = new ArrayList<OOMObject>();
while(true){
list.add(new OOMObject());;
}

}
}


运行结果:

Exceptioninthread "main" java.lang.OutOfMemoryError: Java heap space

分析:内存泄漏Memory Leak,对象应该被回收却没有

内存溢出Memory Overflow空间不够,通过-Xms设置堆最小值,-Xmx设置堆最大值,缩短对象生命周期和持有时间,减少程序运行期的内存消耗。



2. 虚拟机栈和本地方法栈溢出

-Xss设置栈容量

递归导致*Error

/**
* 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;
}
}

}
运行结果:

stacklength: 2275

Exceptionin thread "main"java.lang.*Error

   atcom.java.vm.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:10)

分析:

只要单线程,不管是栈帧太大,还是虚拟机栈容量太小都抛出*Error

创建线程导致OOM

/**
* VM Args: -Xss2m
*
*/
public class JavaVMStackOOM {
private void dontStop(){
while(true){

}
}
public void stackLeakByThread(){
while(true){
Thread thread = new Thread(new Runnable(){
public void run(){
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args){
JavaVMStackOOM oom =new JavaVMStackOOM();
oom.stackLeakByThread();
}
}
运行结果:

Exceptionin thread "main" java.lang.OutOfMemoryError: unable to create newnative thread

分析:此时的OOM与栈空间的大小无关,减少最大堆和减少栈容量可换取更多线程。

3. 运行时常量池溢出

使用String.intern()这个native方法,向常量池添加内容。该方法的作用,如果池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象,否则,将此String对象包含的字符串添加到常量池中,并返回此String对象的引用。

/**
* VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
*
*/
public class RuntimeConstantPoolOOM {
public static void main(String[] args){
//使用list保持常量池引用,避免Full GC回收常量池行为
List<String> list = new ArrayList<String>();
//10MB的PermSize在integer范围内足够产生OOM了
int i=0;
while(true){
list.add(String.valueOf(i++).intern());
}
}
}
运行结果:

Exceptionin thread "main" java.lang.OutOfMemoryError: PermGen space

4. 方法区溢出

借助CGLib使得方法区出现内存溢出

/**
* VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
*
*/
public class JavaMethodAreaOOM {
static class OOMObject{

}
public static void main(String[] args){
while(true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor(){
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)throws Throwable{
return proxy.invokeSuper(obj, args);
}
});
enhancer.create();
}
}
}
运行结果:

Caused by:java.lang.OutOfMemoryError: PermGen spac

分析:

在动态生成大量class的应用中,如大量JSP或动态产生JSP的应用,要注意类的回收状态。