Java內存區域與內存溢出異常

    先貼上一段參數設置html

JAVA_OPTS=" $JAVA_OPTS -Dspring.profiles.active=test -DLOG_DIR=/home/work/logs 
-Xms2048m -Xmx2048m -Xss1m -XX:NewSize=512m -XX:MaxNewSize=512m -XX:PermSize=128m
-XX:MaxPermSize=512m -XX:SurvivorRatio=6 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -Dfile.encoding=UTF-8
"

    不少時候,將代碼部署到服務器,都會對JAVA_OPTS進行一些操做,大多數狀況對主要兩個知道是幹嗎的,其實的哪copy的算哪的。java

    因此,看了點資料,想寫點東西。spring

    Java虛擬機運行時數據區,主要包括如下部分:方法區、堆,它們是線程共用的部分;虛擬機棧、本地方法棧、程序計數器。下面我服務器

大概講講如上幾個部分。spa

1. 程序計數器。
    線程本身的數據區,用以記錄當前線程所執行的字節碼的行號指示器,主要用於在線程切換過程當中,保證切換後可以恢復到正確的執行位置,此區域是唯一一個在Java虛擬機規範中沒有規定任何OOM狀況的區域。

2. Java虛擬機棧。
    線程獨自擁有,生命週期與線程相同。異常情況,若線程請求棧深度大於虛擬機所容許,則StackOverflowError,若虛擬機棧可動態擴展,在擴展沒法申請獲得足夠內存則OOM。

3. 本地方法棧。
    相對於虛擬機棧爲虛擬機執行Java方法服務,本地方法棧則爲虛擬機使到的Native方法服務。爲線程私有空間。

4. Java堆。
    線程共享區域,在虛擬機啓動時建立,爲GC管理的主要區域。可設置爲固定或者可擴展大小,由-Xmx和-Xms控制,設置成同樣即爲固定。若無空間分配實例,且沒法擴展,則OOM。

5. 方法區。
    線程共享,用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等。此區域也要GC,主要是對常量池回收和對類型的卸載,會有OOM異常。(運行時常量池,用於存放編譯期生成的各類字面量和符號引用,在類加載後存儲,運行期間也可能將新的常量放入池中,如String類的intern()方法)。

 

  來幾個簡單實例。線程

  Java堆溢出:code

package com.wdm.mem;

import java.util.ArrayList;
import java.util.List;

/*
 * VM: -Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError
 */
public class HeapOOM {

    static class OOMObejct {
    }

    public static void main(String[] args) {
        List<OOMObejct> list = new ArrayList<>();
        System.out.println("start");
        int i = 0;
        while (true) {
            i++;
            if (i % 10000 == 0) {
                System.out.println(i);
            }
            list.add(new OOMObejct());
        }
    }
}

輸出以下:htm

start
10000
20000
30000
40000
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid21966.hprof ...
Heap dump file created [2399791 bytes in 0.014 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:261)
    at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
    at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
    at java.util.ArrayList.add(ArrayList.java:458)
    at com.wdm.mem.HeapOOM.main(HeapOOM.java:23)

 

  虛擬機棧和本地方法棧溢出:blog

   

package com.wdm.mem;

/*
 * VM: -Xss160k
 */
public class JavaVMStackSOF {

    private int stackLen = 1;

    public void stackLeak() {
        stackLen++;
        stackLeak();
    }

    public static void main(String[] args) throws Throwable {
        JavaVMStackSOF oom = new JavaVMStackSOF();
        try {
            oom.stackLeak();
        } catch (Throwable e) {
            System.out.println("stack length:" + oom.stackLen);
            throw e;
        }
    }
}


// 輸出:
stack length:771Exception in thread
"main" java.lang.StackOverflowError at com.wdm.mem.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:11) at com.wdm.mem.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12) at com.wdm.mem.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12) at com.wdm.mem.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12) // 設置小於160k時報錯 The stack size specified is too small, Specify at least 160k Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit.

 

運行時常量池溢出:生命週期

Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=1M; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=1M; support was removed in 8.0


package com.wdm.mem;

import java.util.List;
import java.util.ArrayList;

/*
 * VM: -XX:PermSize=10M -XX:MaxPermSize=10M
 */
public class RuntimeConsPoolOOM {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        int i = 0;
        while (true) {
            list.add(String.valueOf(i++).intern());
        }
    }
}


JDK8已經不用這兩個參數了:能夠看這個http://www.cnblogs.com/paddix/p/5309550.html

 

PS:此文由看《深刻理解Java虛擬機:JVM高級特性與最佳實踐》而來

相關文章
相關標籤/搜索