《深入理解Java虚拟机》之实战OutOfMemoryError
Java堆溢出
/**
* -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails
*/
public class HeapOOM {
static class OOMObject{}
public static void main(String[] args) {
ArrayList<OOMObject> list = new ArrayList<>();
while(true) {
list.add(new OOMObject());
}
}
}
打印:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid3336.hprof ...
Heap dump file created [28493647 bytes in 0.078 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:265)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
at java.util.ArrayList.add(ArrayList.java:462)
at com.java.study.jvm.error.HeapOOM.main(HeapOOM.java:14)
Heap
PSYoungGen total 6144K, used 3120K [0x00000000ff980000, 0x0000000100000000, 0x0000000100000000)
eden space 5632K, 55% used [0x00000000ff980000,0x00000000ffc8c118,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
ParOldGen total 13824K, used 13786K [0x00000000fec00000, 0x00000000ff980000, 0x00000000ff980000)
object space 13824K, 99% used [0x00000000fec00000,0x00000000ff976848,0x00000000ff980000)
Metaspace used 3333K, capacity 4500K, committed 4864K, reserved 1056768K
class space used 360K, capacity 388K, committed 512K, reserved 1048576K
虚拟机栈溢出
/**
* -Xss128k
*/
public class StackSof {
private int stackLength = 1;
public void stackLeak() {
stackLength++;
stackLeak();
}
public static void main(String[] args) {
StackSof stackSof = new StackSof();
try{
stackSof.stackLeak();
} catch (Throwable e){
System.out.println("stack length:" + stackSof.stackLength);
throw e;
}
}
}
异常:
stack length:999
Exception in thread "main" java.lang.StackOverflowError
at com.java.study.jvm.error.StackSof.stackLeak(StackSof.java:10)
at com.java.study.jvm.error.StackSof.stackLeak(StackSof.java:11)
局部变量表太大导致栈溢出:
public class StackSof2 {
private static int stackLength = 0;
private static void test() {
long unused1,unused2,unused3,unused4,unused5,
unused6,unused7,unused8,unused9,unused10,
unused11,unused12,unused13,unused14,unused15,
unused16,unused17,unused18,unused19,unused20,
unused21,unused22,unused23,unused24,unused25,
unused26,unused27,unused28,unused29,unused30,
unused31,unused32,unused33,unused34,unused35,
unused36,unused37,unused38,unused39,unused40,
unused41,unused42,unused43,unused44,unused45,
unused46,unused47,unused48,unused49,unused50,
unused51,unused52,unused53,unused54,unused55,
unused56,unused57,unused58,unused59,unused60,
unused61,unused62,unused63,unused64,unused65,
unused66,unused67,unused68,unused69,unused70,
unused71,unused72,unused73,unused74,unused75,
unused76,unused77,unused78,unused79,unused80,
unused81,unused82,unused83,unused84,unused85,
unused86,unused87,unused88,unused89,unused90,
unused91,unused92,unused93,unused94,unused95,
unused96,unused97,unused98,unused99,unused100;
stackLength++;
test();
unused1=unused2=unused3=unused4=unused5=
unused6=unused7=unused8=unused9=unused10=
unused11=unused12=unused13=unused14=unused15=
unused16=unused17=unused18=unused19=unused20=
unused21=unused22=unused23=unused24=unused25=
unused26=unused27=unused28=unused29=unused30=
unused31=unused32=unused33=unused34=unused35=
unused36=unused37=unused38=unused39=unused40=
unused41=unused42=unused43=unused44=unused45=
unused46=unused47=unused48=unused49=unused50=
unused51=unused52=unused53=unused54=unused55=
unused56=unused57=unused58=unused59=unused60=
unused61=unused62=unused63=unused64=unused65=
unused66=unused67=unused68=unused69=unused70=
unused71=unused72=unused73=unused74=unused75=
unused76=unused77=unused78=unused79=unused80=
unused81=unused82=unused83=unused84=unused85=
unused86=unused87=unused88=unused89=unused90=
unused91=unused92=unused93=unused94=unused95=
unused96=unused97=unused98=unused99=unused100 =1L;
}
public static void main(String[] args) {
try{
test();
} catch (Throwable e){
System.out.println("stack length:" + stackLength);
throw e;
}
}
}
异常:
stack length:9094
Exception in thread "main" java.lang.StackOverflowError
at com.java.study.jvm.error.StackSof2.test(StackSof2.java:32)
第三个异常
public class StackOom {
private void dontStop() {
while(true){}
}
private void stackLeakByThread() {
while(true) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args) {
StackOom stackOom = new StackOom();
stackOom.stackLeakByThread();
}
}
这个测试卡死......
运行时常量池导致内存溢出
也可证明运行时常量池在JDK1.8中放在堆内存中进行分配
/**
* -Xms2m -Xmx2m -XX:+PrintGCDetails
*/
public class RunTimeConstantPoolOom {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
short i = 0;
while(true) {
set.add(String.valueOf(i++).intern());
}
}
}
运行结果
[GC (Allocation Failure) [PSYoungGen: 996K->488K(1024K)] 1196K->768K(1536K), 0.0015586 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) --[PSYoungGen: 1000K->1000K(1024K)] 1280K->1504K(1536K), 0.0025075 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
......
[Full GC (Allocation Failure) [PSYoungGen: 512K->512K(1024K)] [ParOldGen: 512K->512K(512K)] 1024K->1024K(1536K), [Metaspace: 3381K->3381K(1056768K)], 0.0046853 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 512K->0K(1024K)] [ParOldGen: 512K->488K(512K)] 1024K->488K(1536K), [Metaspace: 3382K->3382K(1056768K)], 0.0045192 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.HashMap.newNode(HashMap.java:1747)
at java.util.HashMap.putVal(HashMap.java:642)
at java.util.HashMap.put(HashMap.java:612)
at java.util.HashSet.add(HashSet.java:220)
at com.java.study.jvm.RunTimeConstantPoolOom.main(RunTimeConstantPoolOom.java:11)
Heap
PSYoungGen total 1024K, used 33K [0x00000007bfe80000, 0x00000007c0000000, 0x00000007c0000000)
eden space 512K, 6% used [0x00000007bfe80000,0x00000007bfe88718,0x00000007bff00000)
from space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
to space 512K, 43% used [0x00000007bff00000,0x00000007bff37230,0x00000007bff80000)
ParOldGen total 512K, used 488K [0x00000007bfe00000, 0x00000007bfe80000, 0x00000007bfe80000)
object space 512K, 95% used [0x00000007bfe00000,0x00000007bfe7a000,0x00000007bfe80000)
Metaspace used 3414K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 375K, capacity 388K, committed 512K, reserved 1048576K
方法区内存溢出
/**
* -Xms5m -Xmx5m -XX:+PrintGCDetails
*/
public class MethodAreaOom {
public static void main(String[] args) {
while(true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o, args);
}
});
enhancer.create();
}
}
}
class OOMObject{}
当堆内存设置很小时,异常是java.lang.OutOfMemoryError: GC overhead limit exceeded
这个错误是由于JVM花费太长时间执行GC且只能回收很少的堆内存时抛出的。根据Oracle官方文档,默认情况下,如果Java进程花费98%以上的时间执行GC,并且每次只有不到2%的堆被恢复,则JVM抛出此错误。
[Full GC (Ergonomics) [PSYoungGen: 1024K->1019K(1536K)] [ParOldGen: 4023K->4016K(4096K)] 5047K->5035K(5632K), [Metaspace: 25649K->25649K(1073152K)], 0.0124783 secs] [Times: user=0.04 sys=0.00, real=0.02 secs]
[Full GC (Ergonomics) [PSYoungGen: 1024K->977K(1536K)] [ParOldGen: 4016K->4003K(4096K)] 5040K->4980K(5632K), [Metaspace: 25649K->25649K(1073152K)], 0.0121685 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
Exception in thread "main" [Full GC (Ergonomics) [PSYoungGen: 1024K->984K(1536K)] [ParOldGen: 4003K->4001K(4096K)] 5027K->4985K(5632K), [Metaspace: 25660K->25656K(1073152K)], 0.0131160 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
java.lang.OutOfMemoryError: GC overhead limit exceeded
at org.springframework.asm.ByteVector.<init>(ByteVector.java:55)
at org.springframework.asm.ClassWriter.toByteArray(ClassWriter.java:604)
at org.springframework.cglib.core.DebuggingClassWriter$1.run(DebuggingClassWriter.java:78)
[Full GC (Ergonomics) [PSYoungGen: 1024K->975K(1536K)] [ParOldGen: 4001K->4000K(4096K)] 5025K->4976K(5632K), [Metaspace: 25667K->25660K(1073152K)], 0.0165955 secs] [Times: user=0.04 sys=0.00, real=0.02 secs]
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.cglib.core.DebuggingClassWriter.toByteArray(DebuggingClassWriter.java:73)
[Full GC (Ergonomics) [PSYoungGen: 1024K->975K(1536K)] [ParOldGen: 4000K->4000K(4096K)] 5024K->4976K(5632K), [Metaspace: 25663K->25663K(1073152K)], 0.0190048 secs] [Times: user=0.04 sys=0.00, real=0.02 secs]
at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:26)
at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:358)
at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:585)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:131)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319)
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:572)
at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:387)
at com.java.study.jvm.MethodAreaOom.main(MethodAreaOom.java:21)
添加-XX:MetaspaceSize=50m -XX:MaxMetaspaceSize=50m参数后:
[GC (Last ditch collection) [PSYoungGen: 0K->0K(5632K)] 9517K->9517K(19456K), 0.0020960 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[Full GC (Last ditch collection) [PSYoungGen: 0K->0K(5632K)] [ParOldGen: 9517K->9517K(13824K)] 9517K->9517K(19456K), [Metaspace: 50577K->50577K(1095680K)], 0.0263803 secs] [Times: user=0.06 sys=0.00, real=0.02 secs]
Caused by: java.lang.OutOfMemoryError: Metaspace
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:535)
本机直接内存溢出
/**
* -Xms20m -Xmx20m -XX:MaxDirectMemorySize=10M
*/
public class DirectMemoryOom {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) throws Exception{
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe)unsafeField.get(null);
while (true){
unsafe.allocateMemory(_1MB);
}
}
}
异常
Process finished with exit code 137 (interrupted by signal 9: SIGKILL)
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出。