理解Java虛擬機內存分區

一、jvm內存分區

      jvm內存一般分爲程序計數器PC、虛擬機棧、本地方法棧、堆、方法區、運行時常量池、直接內存7大部分,統稱爲Java虛擬機運行時數據區。

1.1、程序計數器PC

        是一塊較小的內存空間、可以看作當前線程所執行的字節碼的行指示器指向當前所執行的字節碼指令的地址,每執行完一條指令PC將自增,然後指像下一條字節碼指令,如此循環可實現字節碼指令的連續執行處理。每條線程有自己獨立的PC、互不影響且獨立存儲,生命週期隨線程創建而開始隨線程退出而結束。此內存區域是唯一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError情況的區域。此區域內存大小不可通過jvm參數進行設置。

1.2、虛擬機棧

       虛擬機棧描述的是Java方法執行時的內存模型,每個方法被執行的時候都會創建一個棧幀用於存儲局部變量表、操作棧、動態鏈接、方法出口等信息。每一個方法從調用至執行完成的過程都對應着一個棧幀在虛擬機棧中的入棧和出棧。虛擬機棧有個深度的概念,深度越深佔用的內存空間越大反之則越小。

      如果虛擬機請求的棧深度超出虛擬機棧的最大允許深度將會拋出StackOverflowError異常,如果虛擬機棧可以動態擴展當擴展到無法申請足夠的內存時會拋出OutOfMemoryError異常。

1.3、本地方法棧

       本地方法棧與虛擬機棧所發揮的作用非常相似,虛擬機棧是爲Java虛擬機執行Java字節碼服務,本地方法棧是爲虛擬機使用到的Native方法服務。本地方法棧也會拋出StackOverflowError和OutOfMemoryError異常。

1.4、堆

      Java堆是Java虛擬機所管理的內存中最大的一塊,被所有線程共享的一塊內存區域,在虛擬機啓動時創建。此區域存放對象的實例,幾乎所有的對象實例都在這裏分配內存。但是隨着JIT編譯器的發展與逃逸分析技術的逐漸成熟,棧上分配、標量替換優化技術的出現,所有的對象都分配在堆上也漸漸變得不那麼絕對了。

      Java堆是垃圾收集器管理的主要區域,因此很多時候又稱爲GC堆。從垃圾收集角度看又可以分爲新生代和老年代,從內存分配角度看,線程共享的Java堆中可能劃分出多個線程私有的分配緩存區(Thread Local Allocation Buffer,TLAB)。

      如果在堆中沒有內存完成實例分配,並且堆也無法再擴展時,將會拋出OutOfMemoryError異常。一般可以通過-Xmx和-Xms控制java堆大小。

1.5、方法區

       方法區與Java堆一樣,是各個線程共享的內存區域,用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據,對於Hotspot虛擬機上開發的和部署的開發者來說很多人願意把方法區稱爲“永久代”。當方法區無法滿足內存分配需求時,將拋出OutOfMemoryError異常。

1.6、運行時常量池

      運行時常量池是方法區的一部分。Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載後存放到方法區的運行時常量池中。

      運行是常量池具備動態性,即並非預置入Class文件中常量池的內容才能進入方法區運行時常量池,運行期也可能將新的常量放入池中,列如String類的intern()方法。

      運行時常量池屬於方法區的一部分,自然受方法去內存的限制,當常量池無法申請到內存是會拋出OutOfMemoryError異常。

1.7、直接內存

      直接內存不是虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的內存區域,但是這部分內存也被頻繁的使用,而且可能導致OutOfMemoryError異常的出現。

      可以理解爲直接在本機上面分配內存,而並非在虛擬機上面分配,其實虛擬機內存也是從本機內存上分配的。這樣做的好處是進行I/O通信時不必將數據在本機內存和虛擬機內存之間來回拷貝。

      值得注意的是,直接內存和虛擬機運行時數據區的內存總和超出物理內存限制的時候會導致OutOfMemoryError異常。

今天的學習到此爲止,理解有誤的地方歡迎指正討論。

 

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