天天看點

java 虛拟機oom 參數配置,深入了解Java虛拟機筆記1: OOM實戰

通過代碼模拟Java虛拟機規範中描述的各個運作時區域記憶體溢出的場景。

首先,虛拟機啟動參數配置如下:

-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8

1

輸出:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

at java.util.Arrays.copyOf(Arrays.java:2245)

at java.util.Arrays.copyOf(Arrays.java:2219)

at java.util.ArrayList.grow(ArrayList.java:213)

at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:187)

at java.util.ArrayList.add(ArrayList.java:411)

at HeapOOM.main(HeapOOM.java:15)

Heap

def new generation   total 9216K, used 8920K [0x32570000, 0x32f70000, 0x32f70000)

eden space 8192K, 100% used [0x32570000, 0x32d70000, 0x32d70000)

from space 1024K, 71% used [0x32d70000, 0x32e26040, 0x32e70000)

to   space 1024K, 0% used [0x32e70000, 0x32e70000, 0x32f70000)

tenured generation   total 10240K, used 5693K [0x32f70000, 0x33970000, 0x33970000)

the space 10240K, 55% used [0x32f70000, 0x334ff7f8, 0x334ff800, 0x33970000)

compacting perm gen  total 12288K, used 135K [0x33970000, 0x34570000, 0x37970000)

the space 12288K, 1% used [0x33970000, 0x33991dd8, 0x33991e00, 0x34570000)

ro space 10240K, 45% used [0x37970000, 0x37df1888, 0x37df1a00, 0x38370000)

rw space 12288K, 54% used [0x38370000, 0x389f04f8, 0x389f0600, 0x38f70000)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

java 虛拟機oom 參數配置,深入了解Java虛拟機筆記1: OOM實戰

2. 虛拟機棧和本地方法棧溢出

java 虛拟機oom 參數配置,深入了解Java虛拟機筆記1: OOM實戰

2.1 StackOverflowError

虛拟機抛出StackOverflowError異常,輸出:Exception in thread "main" java.lang.StackOverflowError

at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:7)

at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:8) ...

1

2

3

4

需要注意,為每個線程的棧配置設定的記憶體越大,反而越容易産生棧記憶體溢出異常。

這個不難了解,每個線程配置設定到棧容量越大,可以建立的線程數量自然就越少,建立線程時就越容易把剩下的記憶體耗盡。

是以,可以通過

“減少記憶體”

的手段來解決棧記憶體溢出問題。

 public class JavaVMStackOOM { private void dontStop() { while (true) {

}

} public void stackLeakByThread() { while (true) {

Thread thread = new Thread(new Runnable() { @Override public void run() {

dontStop();

}

});

thread.start();

}

} public static void main(String[] args) {

JavaVMStackOOM oom = new JavaVMStackOOM();

oom.stackLeakByThread();

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

java 虛拟機oom 參數配置,深入了解Java虛拟機筆記1: OOM實戰

3. 方法區和運作時常量池溢出

JDK 1.7開始逐漸“去永久代化”。在JDK 1.6及之前的版本,由于常量池配置設定在永久代,可以通過-XX:PermSize和-XX:MaxPermSize限制方法區大小,進而間接限制常量池容量。

import java.util.ArrayList; import java.util.List;  public class RuntimeConstantPoolOOM { public static void main(String[] args) { // 使用List保持常量池引用,避免Full GC回收常量池行為 List list = new ArrayList(); // 10MB的PermSize在integer範圍内足夠産生OOM int i =0; while(true) {

list.add(String.valueOf(i++).intern());

}

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

在JDK 1.7及以上,while循環将一直進行下去。

方法區用于存放Class的相關資訊,如類名、通路修飾符、常量池、字段描述、方法描述等。對于這些區域的測試,基本的思想是運作時産生大量的類去填滿方法去,直到溢出。

package com.suning; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;  public class JavaMethodAreaOOM { 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 obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // TODO Auto-generated method stub return proxy.invokeSuper(obj, args);

}

});

enhancer.create();

}

} static class OOMObject {

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

java 虛拟機oom 參數配置,深入了解Java虛拟機筆記1: OOM實戰

4. 本機直接記憶體溢出

運作結果:

Exception in thread "main" java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method)

at DirectMemoryOOM.main(DirectMemoryOOM.java:14)

1

2

3

java 虛拟機oom 參數配置,深入了解Java虛拟機筆記1: OOM實戰

小結

Java堆溢出

虛拟機棧和本地方法棧溢出

方法區和運作時常量池溢出

本機直接記憶體溢出