内存溢出测试(OutOfMemoryError)
Java堆溢出
/**
* -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
*/
publicclassHeapOOM{
staticclassOOMObject{}
publicstaticvoidmain(String[] args){
System.out.println("test");
Listlist=newArrayList<>();
while(true){
list.add(newOOMObject());
}
}
}
结果:
java.lang.OutOfMemoryError:Javaheapspace
Dumpingheaptojava_pid3404.hprof...
Heapdumpfilecreated[22045981 bytes in 0.663 secs]
分析:
内存泄露
导致GC无法自动回收
分析与GC Roots 相关联的路径
内存溢出
检查虚拟机堆参数(-Xmx与-Xms)
虚拟机栈与本地方法栈溢出
/**
* VM Args: -Xss128k
*/
publicclassStackOverFlow{
privateintstackLength =1;
publicvoidstackLeak(){
stackLength ++;
stackLeak();
}
publicstaticvoidmain(String[] args){
StackOverFlow oom =newStackOverFlow();
try{
oom.stackLeak();
}catch(Throwable e){
System.out.println("stack length:"+oom.stackLength);
throwe;
}
}
}
结果:
Exceptioninthread"main"java.lang.StackOverflowError
stacklength:2271
atcom.laowang.vm.StackOverFlow.stackLeak(StackOverFlow.java:9)
atcom.laowang.vm.StackOverFlow.stackLeak(StackOverFlow.java:10)
atcom.laowang.vm.StackOverFlow.stackLeak(StackOverFlow.java:10)
atcom.laowang.vm.StackOverFlow.stackLeak(StackOverFlow.java:10)
以下省略.....
方法区和运行时常量溢出
/**
* VM Args -XX:PermSize=10M -XX:MaxPermSize=10M
* jdk1.6以前的版本,常量池分配在永久代,可以使用以上的参数来限值方法区的大小。
* jdk1.7以后逐步 ”去永久代“
*/
publicclassRuntimeConstantPoolOOM{
publicstaticvoidmain(String[] args){
//使用List保持着常量池引用,避免Full GC回收常量池行为
Listlist=newArrayList<>();
inti =0;
while(true){
//intern()方法的作用是如果常量池中有则返回,如果没有则放入常量池再返回
list.add(String.valueOf(i++).intern());
}
}
}
结果:
Exceptioninthread"main"java.lang.OutOfMemoryError:PermGenspace
atjava.lang.String.intern(Nativemethod)
atcom.laowang.vm.RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:10)
引申:String.intern()返回引用测试
publicclassStringIntern{
publicstaticvoidmain(String[] args){
String str1 =newStringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern() == str1);
String str2 =newStringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == str2);
}
}
结果:
jdk1.6:falsefalse
jdk1.7:truefalse
分析:
jdk1.6:
intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中实例的引用
StringBuilder创建的字符串实例在堆上
不是同一个引用,所以都是false
jdk1.7:
intern()方法不会复制实例,只是在常量池中记录首次出现的实例引用
是同一个引用
方法区OOM代码
/**
* VM Args -XX:PermSize=10M -XX:MaxPermSize=10M
* 同样在jdk1.7以后没有效果
* 在jdk1.6以前会出现OOM
*/
publicclassJavaMethodAreaOOM{
publicstaticvoidmain(finalString[] args){
while(true){
Enhancer enhancer =newEnhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(newMethodInterceptor() {
publicObjectintercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)throwsThrowable{
returnmethodProxy.invokeSuper(objects,args);
}
});
enhancer.create();
}
}
staticclassOOMObject{
}
}
结果:
Causedby:java.lang.OutOfMemoryError:PermGenspace
atjava.lang.ClassLoader.defineClass1(NativeMethod)
atjava.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
atjava.lang.ClassLoader.defineClass(ClassLoader.java:616)
... 8more
本机直接内存溢出
直接内存可以使用-XX:MaxDirectMemorySize指定
默认与Java堆最大值(-Xms指定)一样
/**
* VM Args: -Xmx20M -XX:MaxDirectMemorySize=10M
*/
publicclassDirectMemoryOOM{
privatestaticfinalint_1MB =1024*1024;
publicstaticvoidmain(String[] args) throws Exception{
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafeunsafe= (Unsafe)unsafeField.get(null);
while(true){
unsafe.allocateMemory(_1MB);
}
}
}
结果:
Exceptioninthread"main"java.lang.OutOfMemoryError
atsun.misc.Unsafe.allocateMemory(NativeMethod)
atcom.laowang.vm.DirectMemoryOOM.main(DirectMemoryOOM.java:18)
-END-