1.jvm的內部體系結構淺析html
2.jvm的幾個運行時數據區域java
3.jvm的內存溢出異常jvm
在Java虛擬機規範的描述中,除了PC(程序計數器)寄存器外,虛擬機內存的其餘幾個運行時區域都有發生OutOfMemoryError異常的可能。當發生OutOfMemoryError異常時,沒法用try...catch捕捉。ide
在開始講解以前,在這裏先簡單介紹下虛擬機啓動相關的一些內存設置參數。由於OutOfMemoryError異常發生,與這些參數的設置密切相關。oop
舉例說明含義:post
-Xss128k測試
每一個線程的java棧大小,一個線程java棧全部棧幀大小總和最大容許的尺寸128k。
-Xms128m
表示JVM Heap(堆內存)最小尺寸128MB,初始分配
-Xmx512m
表示JVM Heap(堆內存)最大容許的尺寸256MB,按需分配。url
-XX:PermSize=20Mspa
設置方法區的初始大小線程
-XX:MaxPermSize=30M
設置方法區的最大值
Java棧溢出
在Java虛擬機規範中,對這個區域規定了兩種異常情況:StackOverflowError和OutOfMemoryError異常。
1.StackOverflowError異常
每當java程序代碼啓動一個新線程時,Java虛擬機都會爲它分配一個Java棧。Java棧以幀爲單位保存線程的運行狀態。當線程調用java方法時,虛擬機壓入一個新的棧幀到該線程的java棧中。只要這個方法尚未返回,它就一直存在。若是線程的方法嵌套調用層次太多(如遞歸調用),隨着java棧中幀的逐漸增多,最終會因爲該線程java棧中全部棧幀大小總和大於-Xss設置的值,而產生StackOverflowError內存溢出異常。例子以下:
/** * VM Args: -Xss128k */ public class Test { private int count = 0; public static void main(String[] args) { new Test().method(); } public void method() { System.out.println(++count); method(); } }
-Xss爲128k。其中的一次測試結果爲,當count的值累加到2312時,發生以下異常:
Exception in thread "main" java.lang.StackOverflowError at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:58) at sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(UTF_8.java:392) at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:447) at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:544) at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:252) at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:106) at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190) at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111) at java.io.PrintStream.write(PrintStream.java:476) at java.io.PrintStream.print(PrintStream.java:547) at java.io.PrintStream.println(PrintStream.java:686) at jvm.Test.method(Test.java:17)修改-Xss爲1280k。其中的一次測試結果爲,當count的值累加到26888時,發生StackOverflowError異常。隨着-Xss參數值的增大,能夠嵌套的方法調用層次也相應增長。
綜上所述,StackOverflowError異常是因爲方法調用的層次太深,最終致使爲某個線程分配的全部棧幀大小總和大於-Xss設置的值,從而發生StackOverflowError異常。
2.OutOfMemoryError異常
java程序代碼啓動一個新線程時,沒有足夠的內存空間爲該線程分配java棧(一個線程java棧的大小由-Xss參數肯定),jvm則拋出OutOfMemoryError異常。例子以下:
/**
* VM Args: -Xss128k
*/
public class Test {
public static void main(String[] args) {
int count = 0;
while (true) {
Thread thread = new Thread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(5000);
} catch (Exception e) {}
}
}
});
thread.start();
System.out.println(++count);
}
}
}
-Xss爲128k。其中的一次測試結果爲,當count的值累加到11887時,發生以下異常:
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:640) at jvm.Test.main(Test.java:20)
修改-Xss爲1280k。其中的一次測試結果爲,當count的值累加到1270時,發生OutOfMemoryError異常。隨着-Xss參數值的增大,java程序能夠建立的總線程數越少。
Java堆溢出
Java堆用於儲存對象實例。當須要爲對象實例分配內存,而堆的內存佔用又已經達到-Xmx設置的最大值。將會拋出OutOfMemoryError異常,例子以下:
/**
* VM Args: -Xmx5m
*/
public class Test {
public static void main(String[] args) {
int count = 0;
List<Object> list = new ArrayList<Object>();
while (true) {
list.add(new Object());
System.out.println(++count);
}
}
}
-Xmx爲5m。其中的一次測試結果爲,當count的值累加到297868時,發生以下異常:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:2760) at java.util.Arrays.copyOf(Arrays.java:2734) at java.util.ArrayList.ensureCapacity(ArrayList.java:167) at java.util.ArrayList.add(ArrayList.java:351) at jvm.Test.main(Test.java:15)
修改-Xmx爲10m。其中的一次測試結果爲,當count的值累加到670205時,發生OutOfMemoryError異常。隨着-Xmx參數值的增大,java堆中能夠存儲的對象也越多。
方法區溢出
方法區用於存放java類型的相關信息,如類名、訪問修飾符、常量池、字段描述、方法描述等。在類裝載器加載class文件到內存的過程當中,虛擬機會提取其中的類型信息,並將這些信息存儲到方法區。當須要存儲類信息而方法區的內存佔用又已經達到-XX:MaxPermSize設置的最大值。將會拋出OutOfMemoryError異常。對於這種狀況的測試,基本的思路是運行時產生大量的類去填滿方法區,直到溢出。這裏須要藉助CGLib直接操做字節碼運行時,生成了大量的動態類。例子以下:
/**
* VM Args: -XX:MaxPermSize=50M
*/
public class Test {
public static void main(String[] args) {
int count = 0;
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Test.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
return proxy.invoke(obj, args);
}
});
enhancer.create();
System.out.println(++count);
}
}
}
-XX:MaxPermSize爲50m。其中的一次測試結果爲,當count的值累加到3953時,發生以下異常:
Caused by: java.lang.OutOfMemoryError: PermGen space at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631) at java.lang.ClassLoader.defineClass(ClassLoader.java:615) ... 8 more
修改-XX:MaxPermSize爲100m。其中的一次測試結果爲,當count的值累加到8022時,發生OutOfMemoryError異常。隨着-XX:MaxPermSize參數值的增大,java方法區中能夠存儲的類型數據也越多。
轉:http://www.cnblogs.com/evan2012/archive/2012/05/12/2497086.html