日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java ppt转图片 内存溢出_Java虚拟机内存及内存溢出异常

發布時間:2025/3/15 java 10 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java ppt转图片 内存溢出_Java虚拟机内存及内存溢出异常 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java與C++之間有一堵由內存動態分配和垃圾收集技術所圍成的高墻,墻外面的人想進來,墻里面的人卻想出來。

不知道其他人想出來沒,反正我是沒想出來,為什么這個JVM的運行時內存要這樣設計?。

以下內容中,Java虛擬機(JVM)特指HotSpot虛擬機。

JVM啟動后,整體來看,會把向操作系統申請到的內存空間分成這樣幾個部分:

  • 程序計數器區
  • 虛擬機棧
  • 本地方法棧
  • 方法區
  • 它們在《Java虛擬機規范》中都有相關規定和說明,只是有的區域具體實現細節根據Java虛擬機實現者來決定,《Java虛擬機規范》不做強行要求,例如方法區。下面對這幾個部分進行詳細敘述,在敘述過程中,需要不斷參考下面這個示意圖來幫助理解。

    Java運行時內存布局

    文中示例程序來自
    《深入理解Java虛擬機》
    周志明·著
    如有雷同,不是巧合 ?

    1. 程序計數器區(Program Counter Register)

    這個區域內容指向當前線程所執行字節碼行號,是線程私有區域。和操作系統里面的PC指針類似,只不過這個PC指針指向當前執行的字節碼行號,操作系統的指針指向下一條執行的指令地址。

    需要額外注意的是,如果當前線程在執行Java程序,那么如上所述指向字節碼行號,如果執行的是Native方法,那么這個區域是空(Undefined)的。

    該區域也是唯一一個《Java虛擬機規范》里面沒有 OutOfMemoryError 錯誤的定義的區域。

    2. Java虛擬機棧(VM Stack)

    該區域的內容是Java方法執行的線程內存模型,具體來說,存放的是棧幀,在棧幀中,存放了局部變量表、操作數棧等信息,當一個方法被調用時,就會創建一個棧幀來記錄信息,方法從被調用到返回的過程,也就對應了棧幀從入棧(虛擬機棧)到出棧的過程。顯而易見,這個區域必須是線程私有的,否則就混亂了呀?。

    這個區域在《Java虛擬機規范》中,詳細定義了以下內容:

  • 如果線程所創建的棧幀個數大于虛擬機所允許的個數,那么拋出 StackOverflowError 異常。
  • 如果在創建棧幀的過程中,因為內存不足所失敗了,則會拋出 OutOfMemoryError 異常。
  • 2.1 虛擬機棧異常示例程序

    /**
    ?*?VM?Args:?-Xss128k
    ?*?-Xss:?減小棧內存容量
    ?*?虛擬機棧和本地方法棧測試,拋出?StackOverflow?異常
    ?*/
    public?class?JavaVMStackSOF?{
    ????private?int?stackLength?=?1;

    ????public?void?stackLeak()?{
    ????????stackLength++;
    ????????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.stackLength);
    ????????????throw?e;
    ????????}
    ????}
    }

    對于 OutOfMemoryError 就需要格外小心了,程序如下:

    /**
    ?*?!!?需要先保存當前系統的工作,因為這個程序比較危險。
    ?*?可能會造成系統假死或者其他異常(甚至強制重啟才可以使用)。
    ?*?


    ?*?VM?Args:?-Xss2m
    ?*?-Xss:?減少棧內存容量
    ?*?使用線程來制造內存溢出異常
    ?*/


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

    ????public?void?stackLeakByThread()?{
    ????????while?(true)?{
    ????????????Thread?thread?=?new?Thread(new?Runnable()?{
    ????????????????public?void?run()?{?dontStop();?}
    ????????????});
    ????????????thread.start();
    ????????}
    ????}

    ????public?static?void?main(String[]?args)?{
    ????????JavaVMStackOOM?oom?=?new?JavaVMStackOOM();
    ????????oom.stackLeakByThread();
    ????}
    }

    3. 本地方法棧(Native Method Stack)

    本地方法棧“雷同”虛擬機棧的功能,唯一的區別在于前者記錄的是本地方法的執行記錄,后者是Java程序的執行記錄。

    因為這個區域在《Java虛擬機規范》中并沒有詳細規定本地方法的實現語言和數據結構,所以虛擬機可以根據自己需要來進行擴展。只不過,在HotSpot虛擬機中,是把虛擬機棧和本地方法棧統一放到一起了的。

    在可能拋出的異常類型上,和虛擬機棧一樣樣:

  • 如果線程所創建的棧幀個數大于虛擬機所允許的個數,那么拋出 StackOverflowError 異常。
  • 如果在創建棧幀的過程中,因為內存不足所失敗了,則會拋出 OutOfMemoryError 異常。
  • 4. 堆(Heap)

    此堆非彼堆,不是同一堆?。上篇文章說到的《探索STL:堆數據結構及算法》,和這里的堆完全不是同一個概念。更何況,這個堆是Java虛擬機的東西,那個是C++的東西,兩個混淆了不大好吧?。

    Java堆可以說是整個Java虛擬機中最靈活的地方了,也是最值得研究的地方了,目前好多研究都是圍繞這個區域的垃圾收集(Garbage Collection, GC)展開的。這個區域在Java虛擬機啟動之初就創建好了,給所有線程共享使用,這里存放的唯一內容就是對象實例,拿《Java虛擬機規范》中的描述來說就是:

    The heap is the runtime data area from which memory for all class instances and arrays is allocated.

    這一塊內存是設計成可擴展的,使用參數 -Xmx 和 -Xms 來設定允許的最大內存和允許的最小內存。當內存不夠完成實例的創建也不能完成內存擴展時,將會拋出 OutOfMemoryError 異常。

    4.1 堆內存溢出程序示例

    import?java.util.ArrayList;
    import?java.util.List;
    /**
    ?*?-Xms?設置最小值
    ?*?-Xmx?設置最大值
    ?*?-XX:+HeapDumpOnOutOfMemoryError??當出現內存溢出異常時,Dump出當前的內存轉儲快照
    ?*?VM?Args:?-Xms20m?-Xmx20m?-XX:+HeapDumpOnOutOfMemoryError
    ?*?


    ?*?堆內存溢出異常測試
    ?*/


    class?HeapOOM?{
    ????static?class?OOMObject?{}
    ????public?static?void?main(String[]?args)?{
    ????????List?list?=?new?ArrayList();while?(true)?{
    ????????????list.add(new?OOMObject());
    ????????}
    ????}
    }

    5. 方法區(Method Area)

    這個區域也是線程共享區域,里面存放了被虛擬機加載進來的:

    • 類信息
    • 常量、靜態變量
    • 即時編譯后的程序

    需要注意的是在這里有一個版本分歧,JDK6及以前的版本,方法區使用分代設計來實現該區域,但是JDK7就開始不一樣了,首先是在JDK7吧放在永久代的字符串常量池、靜態變量移出到了本地內存中,到了JDK8,徹底將方法區的分代設計拋棄了,換成了使用本地內存實現的“元空間”代替。

    這個空間在不能滿足新的內存分配需求時,拋出 OutOfMemoryError 異常。

    4.1 方法區內存溢出示例程序

    import?net.sf.cglib.proxy.Enhancer;
    import?net.sf.cglib.proxy.MethodInterceptor;
    import?net.sf.cglib.proxy.MethodProxy;

    import?java.lang.reflect.Method;

    /**
    ?*?VM?Args:?-XX:PermSize=10m?-XX:MaxPermSize=10m?-XX:+HeapDumpOnOutOfMemoryError
    ?*?上面這個設置是沒用的,因為從JDK8開始,HotSpot虛擬機就沒有了永久代這么一說,變成了元空間可通過這樣設置來實現:
    ?*?VM?Args:?-XX:MaxMetaspaceSize=10m
    ?*?-XX:MaxMetaspaceSize=10m?設置最大元空間,默認是-1,即不設置大小(受限于本地)
    ?*?-XX:MetaspaceSize=10m????設置元空間的初始空間大小,以字節為單位,如果達到了該值,就會觸發垃圾收集,并且會調整元空間的大小
    ?*?-XX:MinMetaspaceFreeRatio
    ?*?報錯為:Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
    ?*/
    public?class?JVMMethodAreaOOM?{
    ????static?class?OOMObject?{}

    ????public?static?void?main(String[]?args)?{
    ????????while?(true)?{
    ????????????Enhancer?enhancer?=?new?Enhancer();
    ????????????enhancer.setSuperclass(OOMObject.class);
    ????????????enhancer.setUseCache(false);
    ????????????enhancer.setCallback(new?MethodInterceptor()?{
    ????????????????public?Object?intercept(Object?o,?Method?method,?Object[]?objects,?MethodProxy?methodProxy)?throws?Throwable?{
    ????????????????????return?methodProxy.invokeSuper(o,?objects);
    ????????????????}
    ????????????});
    ????????????enhancer.create();
    ????????}
    ????}
    }

    5.1 運行時常量池(Runtime Constant Pool)

    這是一個神奇的區域?

    首先它是方法區的一個部分,在類文件中有一部分內容是常量池表,這部分內容存放了在編譯器生成的字面量和符號引用,在類加載后放到方法區的運行時常量中。

    運行時常量池具備動態特性,也就是說可以將運行期產生的常量放到池子中,例如 String.intern() 方法。

    同方法區異常一樣,在內存申請不足的時候,會拋出 OutOfMemoryError 異常。

    5.1.1 運行時常量池異常示例程序

    import?java.util.HashSet;
    import?java.util.Set;
    /**
    ?*?VM?Args:?-Xmx2m
    ?*?因為JDK8已經把原本放在永久代的字符串常量池移到了?Java堆?中,
    ?*?所以限制了堆大小之后,會模擬出來堆內存溢出異常
    ?*/
    public?class?RuntimeConstantPoolOOM?{
    ????public?static?void?main(String[]?args)?{
    ????????Set?set?=?new?HashSet();short?i?=?0;while?(true)?{
    ????????????set.add(String.valueOf(i++).intern());
    ????????}
    ????}
    }

    6. 直接內存(Direct Memory)

    如果查《Java虛擬機規范》,并不能夠找到這部分內容,也就是說它并不是虛擬機的一部分,但是這部分內容經常被使用到,舉個例子:JDK1.4之后出現的NIO(New Input/Output),記起來了吧??這個基于緩沖區(Buffer)和通道(Channel)的I/O模型。使用本地函數直接分配堆外內存,然后通過 DirectByteBuffer 對象作為申請到的堆外內存引用,可以省去在Java堆和本地內存中來回復制數據。

    很明顯,既然不屬于Java虛擬機的范疇,自然也就不會被Java虛擬機大小所限制,不過,仍然要受到本機內存的限制。當內存申請失敗時,會拋出 OutOfMemoryError 異常。

    6.1 直接內存異常示例程序

    import?sun.misc.Unsafe;
    import?java.lang.reflect.Field;
    /**
    ?*?VM?Args:?-Xmx20m?-XX:MaxDirectMemorySize=10m
    ?*?-XX:MaxDirectMemorySize??設置最大直接內存,默認是和Java堆保持一致
    ?*/
    public?class?DirectMemoryOOM?{
    ????private?static?final?int?_1MB?=?1024?*?1024;
    ????public?static?void?main(String[]?args)?throws?IllegalAccessException?{
    ????????Field?unsafeField?=?Unsafe.class.getDeclaredFields()[0];
    ????????unsafeField.setAccessible(true);
    ????????Unsafe?unsafe?=?(Unsafe)?unsafeField.get(null);
    ????????while?(true)?{
    ????????????unsafe.allocateMemory(_1MB);
    ????????}
    ????}
    }

    好了,圖里面出現的各個區域所能出現的問題,已經差不多都遇到了(這種主動犯錯的機會可不多?),也該休息休息然后去復習考試了嗚嗚嗚嗚嗚?……

    總結

    以上是生活随笔為你收集整理的java ppt转图片 内存溢出_Java虚拟机内存及内存溢出异常的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。