運行時內存區域這塊,如果不將內存各個區域做什麼的瞭解清楚,後面看的會很累。
之前將JVM運行時內存區域的內容,整理在了一篇文章中。
在後續深入、細緻的學習中,整理的內容越來越多,一篇的話,會導致篇幅過長。
所以將《JVM運行時內存區域詳解》分爲以下幾個章節:
這裏將《Java虛擬機規範中文版》上傳了,點擊下面鏈接,即可下載
目錄
《Java Virtual Machine Specification Java SE 7 中文版》
《Java Virtual Machine's Internal Architecture》
方法區
《深入理解Java虛擬機:JVM高級特性與最佳實踐》
方法區也是個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、及時編譯器編譯後的代碼等數據。
雖然Java虛擬機規範把方法區描述爲堆的一個邏輯部分,但它有一個別名叫做:Non-Heap(非堆),目的應該是與Java堆區分開來。
方法區在程序運行時被創建。
它與Java堆的區別除了存儲的信息與Java堆不一樣之外,最大的區別是這一部分Java虛擬機規範中不強制要求實現自動內存管理系統(GC)。
對於在HotSpot虛擬機上開發的開發者來說,很多人更願意將方法區稱爲"永久代",本質上兩者並不等價。
(書中的內容需要好好讀上兩遍,應該能夠理解,這裏暫時不表,下面會做解釋)
《Java Virtual Machine Specification Java SE 7 中文版》
在Java虛擬機中,方法區是可供各條線程共享的運行時內存區域。
方法區與傳統語言中的編譯代碼存儲區或者操作系統進程的正文段的作用非常類似,它存儲了每一個類的結構信息,例如運行
常量池、字段、方法數據、構造函數和普通方法的字節碼內容、還包括一些類、實例、接口初始化時用到的特殊方法。
方法區在虛擬機啓動的時候創建,雖然方法區是堆的邏輯組成部分,但是簡單的虛擬機實現可以選擇在這個區域不實現垃圾蒐集。(不強制虛擬機實現方法區的垃圾蒐集)
方法區的容量可以是固定大小的,也可以隨着程序執行的需求動態擴展,並在不需要過多空間時自動收縮。
方法區在實際內存空間中可以是不連續的。
《Java Virtual Machine's Internal Architecture》
在JVM運行時數據區中,方法區的作用和堆類似,扮演的也是存儲公共數據的角色。
不過方法區存儲的是已加載的代碼(Class-類信息 等編譯後的數據)。
換個角度理解:
可以將其視爲靜態的硬盤。(注意和堆進行區分)
- 虛擬機啓動,虛擬機使用類加載器來定位相應的類文件。
- 類加載器讀入類文件(二進制數據的線性流),並將其傳遞給虛擬機。
- 虛擬機從二進制數據中提取信息,並將信息存儲在方法區中。
- 類中聲明的類(靜態)變量的內存也取自方法區。
永久代和方法區的關係?
簡單的說:
在Java虛擬機規範中,並沒有什麼"永久代"的概念,有的只是一個方法區概念。
HotSpot團隊設計 HotSpot虛擬機時候偷懶,使用 永久代 來 實現 方法區;
這樣子,HotSpot虛擬機的垃圾回收期就可以像管理Java堆一樣管理永久代(方法區)。
其實,只要你理解了 Java虛擬機規範 和 HotSpot虛擬機 兩者之間的關係,很容易就明白這二者的關係了。
(一個是接口規範,一個是接口具體實現)
方法區:Java虛擬機規範。
永久代:HotSpot虛擬機特有(其他虛擬機不瞭解...)。
這裏我貼上從網上找的答案:
https://www.zhihu.com/question/49044988
常量池與永久代
JDK1.7開始,將原本放在"永久代"中的字符串常量池移出。
這個觀點"RednaxelaFX"也在評論中做了解釋:
https://www.zhihu.com/question/49044988
http://openjdk.java.net/jeps/122
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.4