JVM內存管理

Java虛擬機在執行Java程序時,會把它所管理的內存區域在邏輯上劃分爲不同的區,具體如下圖:
Java內存管理

  1. 堆(Heap)
      堆內存是被所有線程共享(因此在堆上分配內存需要加鎖)的一塊內存區域,主要用來存放對象的實例,垃圾回收也主要是回收堆的空間。
      現在收集器基本都採用分代收集算法,Java堆還可以細分爲:新生代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation 也被成爲方法區)。
      
    這裏寫圖片描述
    相關參數:
    -Xms     設置堆內存初始化大小
    -Xmx     設置堆內存最大值
    當堆中沒有可分配的內存並且無法擴展時,將會拋出OutOfMemoryError(OOM)異常

    • 新生代(Young Generation)
        新生代又分爲Eden空間和Survivor空間,Survivor空間又包括From Survivor空間和To Survivor空間兩個相等的邏輯區域。爲了提高效率,JVM會爲每個線程在Eden空間分配一塊私有的分配緩衝區空間(Thread Local Allocation Buffer)TLAB,大小默認爲Enen的1%。
         新生代的對象基本都是”朝夕生死的”,所以在新生代的垃圾回收算法採用的是複製算法,對象優先在Eden區中分配,當Eden區滿的時候(名爲From Survivor區也滿,To Survivor區爲空),虛擬機將發動一次Minor GC,此時,Eden區中存活的對象被複制到”To Survivor“區,”From Survivor“區存活的,年齡到達一定閥值的對象被移動到老年代,沒有達到的被複制到”To Survivor“區
         
      相關參數:
      -Xmn      設置新生代內存大小
      -XX:SurvivorRatio    設置Eden和Survivor空間的大小比例(默認爲 8:1)
      -XX:PretenureSizeThreshold  – 設置超過指定大小的大對象直接分配在老年代中
    • 老年代(Old Generation)
        老年代採用”標記-整理算法“,老年代的對象都沒那麼容易死。
      相關參數:
      -XX:MaxTenuringThreshold  – 設置對象在新生代中存活的次數
    • 永久代(PermanentGeneration)
        又稱爲方法區,被線程共享,用來存放JVM加載的類型信息。包括: 類型基本信息,常量池,字段信息,方法信息,類變量,指向ClassLoader的引用,Class類的引用,方法表等。方法區是全局共享的,在一定條件下也會被GC
      相關參數 :
      -XX:PermSize    –設置Perm區的初始大小
      -XX:MaxPermSize    –設置Perm區的最大值
  2. 棧(Stack)
      Java虛擬機棧是線程私有的,它的生命週期和線程相同,棧描述的是Java方法執行的內存模型:方法執行時創建一個棧幀用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息,一個方法的調用直到完成,對應着一個棧幀在虛擬機棧的入棧和出棧的過程。
    相關參數:
    -Xss    –設置方法棧的最大值

  3. 程序計數器
      程序計數器也是線程私有的,是一塊較小的內存空間,可看作當前線程所執行的字節碼的行號指示器。在虛擬機的概念模型裏,字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。

  4. 本地方法棧
      本地方法棧(Native Method Stacks)與虛擬機棧所發揮的作用是非常相似的,其區別不過是虛擬機棧爲虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則是爲虛擬機使用到的Native方法服務。虛擬機規範中對本地方法棧中的方法使用的語言、使用方式與數據結構並沒有強制規定,因此具體的虛擬機可以自由實現它。甚至有的虛擬機(譬如Sun HotSpot虛擬機)直接就把本地方法棧和虛擬機棧合二爲一。與虛擬機棧一樣,本地方法棧區域也會拋出StackOverflowError和OutOfMemoryError異常。

  5. 直接內存
      直接內存(Direct Memory)並不是虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的內存區域,但這部分內存也被頻繁的使用,也可能導致OutOfMemoryError異常。
      在JDK1.4中新加入的NIO(New Input/Output)類,引入了一種基於通道(Channel)與緩衝區(Buffer)的 I/O 方式,它可以使用Native函數庫直接分配堆外內存,然後通過一個存儲在Java堆中的DirectByteBuffer對象作爲這塊內存的引用進行操作,這樣能在一些場景中顯著提高性能,因爲避免了在Java堆和Native堆中來回複製數據。
      本機直接內存的分配不受Java堆大小的限制,既是內存,還是受本機總內存大小和處理器尋址空間的限制。在配置虛擬機參數時,根據實際內存設置-Xmx等參數信息,忽略直接內存,使得各個內存區域總和大於物理內存的限制,從而導致動態擴展時出現OutOfMemoryError異常。
      Java被設計成一個安全,可管理的環境,然而 Java HotSpot有一個後門,提供了對低級別的,對直接內存和線程的操作。這個後門是—-sun.misc.Unsafe。這個類在JDK中有廣泛的應用,例如,java.nio和java.util.concurrent

Java直接內存訪問的技巧


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章