JVM內存管理機制

轉載:http://www.cnblogs.com/newyunhe/articles/5001056.html

借鑑:http://blog.csdn.net/suifeng3051/article/details/48292193

一、概述

         Java GC(Garbage Collection,垃圾收集,垃圾回收)機制,是Java與C++/C的主要區別之一,作爲Java開發者,一般不需要專門編寫內存回收和垃圾清理代碼,對內存泄露和溢出的問題,也不需要像C程序員那樣戰戰兢兢。經過這麼長時間的發展,Java GC機制已經日臻完善,幾乎可以自動的爲我們做絕大多數的事情。

雖然java不需要開發人員顯示的分配和回收內存,這對開發人員確實降低了不少編程難度,但也可能帶來一些副作用:

1. 有可能不知不覺浪費了很多內存
2. JVM花費過多時間來進行內存回收
3. 內存泄露
  • 1
  • 2
  • 3
  • 4

       因此,作爲一名java編程人員,必須學會JVM內存管理和回收機制,這可以幫助我們在日常工作中排查各種內存溢出或泄露問題,解決性能瓶頸,達到更高的併發量,寫出更高效的程序。

二、JVM內存空間管理

內存空間劃分爲:Sun JDK在實現時遵照JVM規範,將內存空間劃分爲堆、JVM方法棧、方法區、本地方法棧、PC寄存器。

  • 堆: 堆用於存儲對象實例及數組值,可以認爲Java中所有通過new創建的對象的內存都在此分配,Heap中對象所佔用的內存由GC進行回收,在32位操作系統上最大爲2GB,在64位操作系統上則沒有限制,其大小可通過-Xms和-Xmx來控制,-Xms爲JVM啓動時申請的最小Heap內存,默認爲物理內存的1/64但小於1GB;-Xmx爲JVM可申請的最大Heap內存,默認爲物理內存的1/4但小於1GB,默認當空餘堆內存小於40%時,JVM會增大Heap到-Xmx指定的大小,可通過-XX:MinHeapFreeRatio=來指定這個比例;當空餘堆內存大於70%時,JVM會減小Heap的大小到-Xms指定的大小,可通過-XX:MaxHeapFreeRatio=來指定這個比例,對於運行系統而言,爲避免在運行時頻繁調整Heap 的大小,通常將-Xms和-Xmx的值設成一樣。
  • JVM方法棧: 爲線程私有,其在內存分配上非常高效。當方法運行完畢時,其對應的棧幀所佔用的內存也會自動釋放。當JVM方法棧空間不足時,會拋出StackOverflowError的錯誤,在Sun JDK中可以通過-Xss來指定其大小。
  • 方法區: 要加載的類的信息(名稱、修飾符等)、類中的靜態變量、類中定義爲final類型的常量、類中的Field信息、類中的方法信息。方法區域也是全局共享的,在一定條件下它也會被GC,當方法區域要使用的內存超過其允許的大小時,會拋出OutOfMemory的錯誤信息。在Sun JDK中這塊區域對應Permanet Generation,又稱爲持久代,默認最小值爲16MB,最大值爲64MB,可通過-XX:PermSize及-XX:MaxPermSize來指定最小值和最大值。
  • 本地方法棧: 用於支持native方法的執行,存儲了每個native方法調用的狀態。在Sun JDK的實現中,和JVM方法棧是同一個。
  • PC寄存器: 佔用的可能爲CPU寄存器或操作系統內存。

三.Java堆和棧的區別

  Java把內存劃分成兩種:一種是棧內存,一種是堆內存。

  在函數中定義的一些基本類型的變量和對象的引用變量都在函數的棧內存中分配。當在一段代碼塊定義一個變量時,Java就在棧中爲這個變量分配內存空間,當超過變量的作用域後,Java會自動釋放掉爲該變量所分配的內存空間,該內存空間可以立即被另作他用。

  堆內存用來存放由new創建的對象和數組。在堆中分配的內存,由Java虛擬機的自動垃圾回收器來管理。在堆中產生了一個數組或對象後,還可以在棧中定義一個特殊的變量,讓棧中這個變量的取值等於數組或對象在堆內存中的首地址,在棧中的這個特殊的變量就變成了數組或者對象的引用變量,以後就可以在程序中使用棧內存中的引用變量來訪問堆中的數組或者對象,引用變量相當於爲數組或者對象起的一個別名,或者代號。

  引用變量是普通變量,定義時在棧中分配內存,引用變量在程序運行到作用域外釋放。而數組&對象本身在堆中分配,即使程序運行到使用new產生數組和對象的語句所在地代碼塊之外,數組和對象本身佔用的堆內存也不會被釋放,數組和對象在沒有引用變量指向它的時候,才變成垃圾,不能再被使用,但是仍然佔着內存,在隨後的一個不確定的時間被垃圾回收器釋放掉。這個也是java比較佔內存的主要原因。但是在寫程序的時候,可以人爲的控制。

四.Java內存泄露和內存溢出

  內存泄漏:分配出去的內存回收不了

  內存溢出:指系統內存不夠用了

五.Java類加載機制

  JVM將類加載過程劃分爲三個步驟:裝載、鏈接和初始化。

  1. 裝載(Load):裝載過程負責找到二進制字節碼並加載至JVM中,JVM通過類的全限定名(com.bluedavy. HelloWorld)及類加載器(ClassLoaderA實例)完成類的加載;
  2. 鏈接(Link):鏈接過程負責對二進制字節碼的格式進行校驗、初始化裝載類中的靜態變量及解析類中調用的接口、類;
  3. 初始化(Initialize):執行類中的靜態初始化代碼、構造器代碼及靜態屬性的初始化。

六.內存回收

  收集器:引用計數收集器、跟蹤收集器

  • 引用計數收集器:對於Java這種面向對象的會形成複雜引用關係(如ObjectB和ObjectC互相引用)的語言而言,引用計數收集器不是非常適合,Sun JDK在實現GC時也未採用這種方式。
  • 跟蹤收集器實現算法:複製(Copying)、標記-清除(Mark-Sweep)和標記-壓縮(Mark-Compact)

  複製:當要回收的空間中存活對象較少時,複製算法會比較高效,其帶來的成本是要增加一塊空的內存空間及進行對象的移動。

  標記-清除:在空間中存活對象較多的情況下較爲高效,但由於標記-清除採用的爲直接回收不存活對象所佔用的內存,因此會造成內存碎片。

  標記-壓縮:在標記-清除的基礎上還須進行對象的移動,成本相對更高,好處則是不產生內存碎片。



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