JDK1.8 JVM記憶體模型

來源:互聯網
上載者:User
一、JDK1.8 JVM記憶體模型概覽

這裡介紹的是JDK1.8 JVM記憶體模型。1.8同1.7比,最大的差別就是:中繼資料區取代了永久代。元空間的本質和永久代類似,都是對JVM規範中方法區的實現。不過元空間與永久代之間最大的區別在於:中繼資料空間並不在虛擬機器中,而是使用本地記憶體二、各地區介紹 1. 程式計數器

每個線程一塊,指向當前線程正在執行的位元組碼代碼的行號。如果當前線程執行的是native方法,則其值為null。 2. Java虛擬機器棧


線程私人,每個線程對應一個Java虛擬機器棧,其生命週期與線程同進同退。每個Java方法在被調用的時候都會建立一個棧幀,併入棧。一旦完成調用,則出棧。所有的的棧幀都出棧後,線程也就完成了使命。 3. 本地方法棧

功能與Java虛擬機器棧十分相同。區別在於,本地方法棧為虛擬機器使用到的native方法服務。不多說。 4. 堆


堆是JVM記憶體佔用最大,管理最複雜的一個地區。其唯一的用途就是存放對象執行個體:所有的對象執行個體及數組都在對上進行分配。1.7後,字串常量池從永久代中剝離出來,存放在堆中。堆有自己進一步的記憶體分塊劃分,按照GC分代收集角度的劃分請參見上圖。 4.1 堆空間記憶體配置(預設情況下) 老年代 : 三分之二的堆空間 年輕代 : 三分之一的堆空間
eden區: 8/10 的年輕代空間 survivor0 : 1/10 的年輕代空間 survivor1 : 1/10 的年輕代空間

命令列上執行如下命令,查看所有預設的jvm參數

java -XX:+PrintFlagsFinal -version
輸出

輸出有大幾百行,這裡只取其中的兩個有關聯的參數

[Global flags]    uintx InitialSurvivorRatio                      = 8                                   {product}    uintx NewRatio                                  = 2                                   {product}    ... ...java version "1.8.0_91"Java(TM) SE Runtime Environment (build 1.8.0_91-b14)Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)
參數解釋
參數 作用
-XX:InitialSurvivorRatio 新生代Eden/Survivor空間的初始比例
-XX:Newratio Old區 和 Yong區 的記憶體比例
一道推算題

預設參數下,如果僅給出eden區40M,求堆空間總大小

根據比例可以推算出,兩個survivor區各5M,年輕代50M。老年代是年輕代的兩倍,即100M。那麼堆總大小就是150M。 4.2 字串常量池

JDK1.7 就開始“去永久代”的工作了。 1.7把字串常量池從永久代中剝離出來,存放在堆空間中。 a. jvm參數配置

-XX:MaxPermSize=10m-XX:PermSize=10m-Xms100m-Xmx100m-XX:-UseGCOverheadLimit
b. 測試代碼
public class StringOomMock {    public static void main(String[] args) {        try {            List<String> list = new ArrayList<String>();            for (int i = 0; ; i++) {                System.out.println(i);                list.add(String.valueOf("String" + i++).intern());            }        } catch (java.lang.Exception e) {            e.printStackTrace();        }    }}
c. jdk1.6 下的運行結果

jdk1.6 環境下是永久代OOM

153658153660Exception in thread "main" java.lang.OutOfMemoryError: PermGen space    at java.lang.String.intern(Native Method)    at com.jd.im.StringOomMock.main(StringOomMock.java:17)
d. jdk1.7 下的運行結果

jdk1.7 下是堆OOM,並且伴隨著頻繁的FullGC, CPU一直高位運行

2252792225279422527962252798*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message can't create name string at ../../../src/share/instrument/JPLISAgent.c line: 807Exception in thread "main" java.lang.OutOfMemoryError: Java heap space    at java.nio.CharBuffer.wrap(CharBuffer.java:369)    at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265)    at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)    at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)    at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)    at java.io.PrintStream.write(PrintStream.java:526)    at java.io.PrintStream.print(PrintStream.java:597)    at java.io.PrintStream.println(PrintStream.java:736)    at com.jd.im.StringOomMock.main(StringOomMock.java:16)
e. jdk1.8 下的運行結果

jdk1.8的運行結果同1.7的一樣,都是堆空間OOM。

223689822369002236902Exception in thread "main" java.lang.OutOfMemoryError: Java heap space    at java.lang.Integer.toString(Integer.java:403)    at java.lang.String.valueOf(String.java:3099)    at java.io.PrintStream.print(PrintStream.java:597)    at java.io.PrintStream.println(PrintStream.java:736)    at com.jd.im.StringOomMock.main(StringOomMock.java:16)
5. 中繼資料區

中繼資料區取代了1.7版本及以前的永久代。中繼資料區和永久代本質上都是方法區的實現。方法區存放虛擬機器載入的類資訊,靜態變數,常量等資料。
中繼資料區OOM測試: a. jvm參數配置

-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=50m
b. 測試代碼

藉助cglib架構產生新類。

public class MetaSpaceOomMock {    public static void main(String[] args) {        ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();        while (true) {            Enhancer enhancer = new Enhancer();            enhancer.setSuperclass(MetaSpaceOomMock.class);            enhancer.setCallbackTypes(new Class[]{Dispatcher.class, MethodInterceptor.class});            enhancer.setCallbackFilter(new CallbackFilter() {                @Override                public int accept(Method method) {                    return 1;                }                @Override                public boolean equals(Object obj) {                    return super.equals(obj);                }            });            Class clazz = enhancer.createClass();            System.out.println(clazz.getName());            //顯示數量資訊(共載入過的類型數目,當前還有效類型數目,已經被卸載的類型數目)            System.out.println("total: " + loadingBean.getTotalLoadedClassCount());            System.out.println("active: " + loadingBean.getLoadedClassCount());            System.out.println("unloaded: " + loadingBean.getUnloadedClassCount());        }    }}
c. 運行輸出:
jvm.MetaSpaceOomMock$$EnhancerByCGLIB$$567f7ec0total: 6265active: 6265unloaded: 0jvm.MetaSpaceOomMock$$EnhancerByCGLIB$$3501581btotal: 6266active: 6266unloaded: 0Exception in thread "main" net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null    at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:345)    at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492)    at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:93)    at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:91)    at net.sf.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)    at java.util.concurrent.FutureTask.run(FutureTask.java:266)    at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)    at net.sf.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)    at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116)    at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291)    at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480)    at net.sf.cglib.proxy.Enhancer.createClass(Enhancer.java:337)    at jvm.MetaSpaceOomMock.main(MetaSpaceOomMock.java:38)Caused by: java.lang.reflect.InvocationTargetException    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 net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:413)    at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:336)    ... 12 moreCaused by: java.lang.OutOfMemoryError: Metaspace    at java.lang.ClassLoader.defineClass1(Native Method)    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)    ... 17 more

如果是1.7的jdk,那麼報OOM的將是PermGen地區。 6. 直接記憶體

jdk1.4引入了NIO,它可以使用Native函數庫直接分配堆外記憶體。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.