简述:
《深入理解Java虚拟机》一书第2张阅读笔记
1. Java堆溢出
jvm启动参数设置
-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
-Xms和-Xmx参数设置一样可以避免堆自动扩展
-XX:+HeapDumpOnOutOfMemoryError 可以让虚拟机在出现内存溢出异常时,Dump出当前的内存堆转储快照一边时候进行分析
-Xmn10M 设置年轻代的大小为10M
-XX:SurvivorRatio 设置年轻代中Eden区和单个survivor区的配置比为8
要保证GC roots到对象之间有可达路径来避免垃圾回收机制清除这些对象
(书上可能有一处问题,不能用ArrayList,由于其在扩容时候会执行Array.copy方法,导致在add之前,先发生array申请memeory的报错)
所以此处用LinkedList代替。
package com.anialy.test.jvm.outofmemeoryerror;
import java.util.LinkedList;
import java.util.List;
/**
* 堆溢出
*/
public class HeapOOM {
public static void main(String[] args) {
List<HeapOOM> list = new LinkedList<HeapOOM>();
while(true){
list.add(new HeapOOM());
}
}
}
报错如下,
2. 栈溢出
package com.anialy.test.jvm.outofmemeoryerror;
/**
* 栈溢出
*/
public class StackSOF {
private static int stackHeight = 0;
public static void stackLeak(){
StackSOF.stackHeight++;
System.out.printf("stack height: %d\n", stackHeight);
stackLeak();
}
public static void main(String[] args) {
try{
stackLeak();
}catch(Exception e){
System.out.printf("stack height: %d\n", stackHeight);
}
}
}
输出:
增大线程堆栈高度的方式,
1) 减少最大堆容量 -Xmx ,由于内存主要是由Xmx最大堆容量和MaxPermSize最大方法区容量占用的
剩余的内存空间只留给了虚拟机栈和本地方法栈
2)增大栈容量 -Xss100M (不合理 只是作测试)
这时候发现堆栈可达高度变大了
3. 运行时常量池溢出
启动参数:
-Xms20M -Xmx20M -Xmn10M
ConstantPoolOOM.java
package com.anialy.test.jvm.outofmemeoryerror;
import java.util.LinkedList;
import java.util.List;
/**
* 运行时常量池溢出
*/
public class ConstantPoolOOM {
public static void main(String[] args) {
List<String> list = new LinkedList<String>();
int i = 0;
while(true){
list.add(String.valueOf(i++));
}
}
}
报错输出:
4. 方法区溢出
package com.anialy.test.jvm.outofmemeoryerror;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 方法区溢出
* 需要使用Cglib进行对类的字节码增强
*/
public class MethodAreaOOM {
public static void main(String[] args) {
while(true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MethodAreaOOM.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();
}
}
}
5.直接内存Direct Memory溢出
直接设置DirectMemory大小
-XX:MaxDirectMemorySize=128m
DirectMemoryOOM
package com.anialy.test.jvm.outofmemeoryerror;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import sun.misc.Unsafe;
import org.springframework.objenesis.instantiator.sun.UnsafeFactoryInstantiator;
/**
* 直接内存 溢出
*/
public class DirectMemoryOOM {
private static final int _1MB = 1024*1024;
private Unsafe unsafe;
public static void main(String[] args)
throws IllegalArgumentException, IllegalAccessException {
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while(true){
unsafe.allocateMemory(_1MB);
}
}
}
输出: