1. 程式人生 > >Java基礎總結(三)

Java基礎總結(三)

首先弄清幾個概念: 
1.方法區(method area)只是JVM規範中定義的一個概念,用於儲存類資訊、常量池、靜態變數、JIT編譯後的程式碼等資料,具體放在哪裡,不同的實現可以放在不同的地方。永久代是HotSpot虛擬機器特有的概念,是對方法區的實現,別的JVM沒有永久代的概念。(雖然去除了永久代,但是方法區作為概念上的區域仍然存在) 
2.在JDK8中,JDK8的HotSpot VM已經是以前的HotSpot VM與JRockit VM的合併版,也就是傳說中的“HotRockit”,只是產品里名字還是叫HotSpot VM。所以對於說JDK8去除永久代換成元空間的說法,就是默指的合併後的HotSpot虛擬機器。 
3.為什麼要將永久代去除呢? 
一方面是節省空間,避免了常見的永久記憶體錯誤:java.lang.OutOfMemoryError: PermGen問題。另一方面是為了整合JRockit,因為JRockit沒有永代區這樣類似的空間。 
其實,從jdk7開始,就開始了永久代的轉移工作,將譬如符號引用(Symbols)轉移到了native heap;字面量(interned strings)轉移到了java heap;等。但是指導JDK8永久代才被元空間替代。 
4.元空間又是什麼呢?以前儲存在永久代裡面的資料現在存在了哪裡? 
元空間是一塊與堆不相連的本地記憶體。原本存在永久代的資料,一部分移到了java堆裡面,一部分移到了本地記憶體裡面(即元空間)(文件中原句:Move part of the contents of the permanent generation in Hotspot to the Java heap and the remainder to native memory.) 。永久代中原來儲存的字串常量(池)、符號引用(這兩個在jdk7普遍就已經將其放在堆上了)和類的靜態變數現在儲存在java堆中,其餘的資料作為元資料儲存在元空間中。 
5.什麼是元資料呢? 
元資料是資料的資料或者叫做用來描述資料的資料或者叫做資訊的資訊。(比如原本方法區儲存的類資訊、即時編譯器編譯後的程式碼等),也可以把元資料簡單的理解成,最小的資料單位。元資料可以為資料說明其元素或屬性(名稱、大小、資料型別、等),或其結構(長度、欄位、資料列),或其相關資料(位於何處、如何聯絡、擁有者)。 
6.元空間詳細:http://blog.csdn.net/lk7688535/article/details/51767460

java虛擬機器在執行java程式的過程中會把它所管理的記憶體劃分為若干的不同的資料區域。這些區域各有用途和各自的建立和銷燬的時間。下面介紹一下jvm在執行時的資料區域。 
首先看一下執行時資料區的總體結構與相關資訊(這是jdk7及其以前的元件圖)

執行緒共享區域:方法區、堆、本地庫介面
執行緒私有區域:虛擬機器棧(VM Stack)、本地方法棧(Native Stack)、程式計數器
程式計數器(Program Counter Register) 
佔有較小的記憶體空間
可以看作是當前所執行位元組碼的行號指示器
當執行緒執行java方法時,記錄的是正在執行的vm位元組碼指令的地址。若執行的為Native方法,計數器值為空即undefined。
唯一一個在jvm中沒有規定OutOfMemoryError異常的區域
java虛擬機器棧(Java Virtual Machine Stacks)

執行緒私有,生命週期與執行緒相同。
描述的是Java方法執行的記憶體模型:每一個方法執行的同時都會建立一個棧幀(Stack Frame),由於儲存區域性變量表、運算元棧、動態連結、方法出口等資訊。每一個方法的執行就對應著棧幀在虛擬機器棧中的入棧,出棧過程。
java記憶體中的常分為堆記憶體和棧記憶體,其中的棧記憶體就可以認為這個VM Stack,或者說是VM Stack中的區域性變量表。
區域性變量表:存放編譯期可知的各種基本資料型別、物件引用型別和returnAddress型別(指向一條位元組碼指令的地址:函式返回地址)。long、double佔用兩個區域性變數控制元件Slot,其餘的佔一個Slot。區域性變量表所需的記憶體空間在編譯期確定,當進入一個方法時,方法在棧幀中所需要分配的區域性變數控制元件是完全確定的,不可動態改變大小。
本地方法棧(Native Method Stack)

為VM提供Native方法服務
本地方法: 
當某個執行緒呼叫一個本地方法時,便不再受虛擬機器的限制。本地方法可以通過本地方法介面來訪問虛擬機器的執行時資料區。
本地方法本質上時依賴於實現的,虛擬機器實現的設計者們可以自由地決定使用怎樣的機制來讓Java程式呼叫本地方法。
任何本地方法介面都會使用某種本地方法棧。當執行緒呼叫Java方法時,虛擬機器會建立一個新的棧幀並壓入Java棧。然而當它呼叫的是本地方法時,虛擬機器會保持Java棧不變,不再線上程的Java棧中壓入新的幀,虛擬機器只是簡單地動態連線並直接呼叫指定的本地方法。
本地方法介面需要回調Java虛擬機器中的Java方法時,該執行緒會儲存本地方法棧的狀態並進入到另一個Java棧。
HotSpot虛擬機器中把本地方法棧和虛擬機器棧合二為一。
java堆

JVM中所管理記憶體中的最大的一塊。在虛擬機器啟動時被建立。
唯一的目的是存放物件例項,幾乎所有的物件例項和陣列都是在這裡分配記憶體。(JVM規範中說的是所有的,但是隨著JIT便編譯器的發展和逃逸技術分析的成熟,一些例項可以不在這個區域分配記憶體)
堆是垃圾收集管理的主要區域,所以也會被稱為”GC堆“
淺堆和深堆 
淺堆(Shallow Heap)和深堆(Retained Heap)是兩個非常重要的概念,它們分別表示一個物件結構所佔用的記憶體大小和一個物件被GC回收後,可以真實釋放的記憶體大小。
淺堆(Shallow Heap)是指一個物件所消耗的記憶體。在32位系統中,一個物件引用會佔據4個位元組,一個int型別會佔據4個位元組,long型變數會佔據8個位元組,每個物件需要佔用8個位元組。
深堆(Retained Heap)的概念略微複雜。要理解深堆,首先需要了解保留集(Retained Set)。物件A的保留集指當物件A被垃圾回收後,可以被釋放的所有物件集合(包括物件A本身),即物件A的保留集可以被認為是隻能通過物件A被直接或間接訪問到的所有物件的集合。通俗地說,就是指僅被物件A所持有的物件的集合。深堆是指物件的保留集中所有的物件的淺堆大小之和。
例如:物件A引用了C和D,物件B引用了C和E。那麼物件A的淺堆大小隻是A本身,不含C和D,而A的實際大小為A、C、D三者之和。而A的深堆大小為A與D之和,由於物件C還可以通過物件B訪問到,因此不在物件A的深堆範圍內。
方法區

前面已經介紹方法區在JDk8之後的的變動
JDK7及之前版本的方法區(Method Area)和Java堆一樣,是各個執行緒共享的記憶體區域,用於儲存已經被虛擬機器載入的類資訊、常量、靜態常量、即時編譯器編譯後的程式碼等資料。
雖然Java虛擬機器規範把方法區描述為堆的一個邏輯部分,但它有另外一個名字叫Non-Heap(非堆)。
兩個子區域: 
持久代: 這個區域會儲存包括類定義、結構、欄位、方法(資料及程式碼)以及常量在內的類相關資料。它可以通過-XX:PermSize及-XX:MaxPermSize來進行調節。如果它的空間用完了,會導致java.lang.OutOfMemoryError: PermGenspace的異常。而JDK8開始,持久代已經被徹底刪除了,取代它的是另一個記憶體區域也被稱為元空間。
存放資料區域:方法區儲存的是每個class的資訊,類載入器引用(classLoader)、執行時常量池(所有常量、欄位引用、方法引用、屬性)、每個方法的名字、型別(如類的全路徑名、型別或介面) 、修飾符(如public、abstract、final)、屬性、每個方法的名字、返回型別、引數型別(按順序)、修飾符、屬性、方法程式碼。
方法區也可被垃圾收集,例如:在HotSpot中將GC分代收集擴充套件至方法區。避免了還要再為方法區編寫GC演算法。
總結:在java中虛擬機器自動記憶體管理機制下,建立物件不需要像c一樣自己進行記憶體的分配,不容易發生記憶體洩漏等問題,但是一旦發生這些問題便不容易去找到發生問題的根源,瞭解JVM的記憶體模型使你可以更容易的查詢原因。
--------------------- 
作者:yoylee_web 
來源:CSDN 
原文:https://blog.csdn.net/CSDN___LYY/article/details/79450860 
版權宣告:本文為博主原創文章,轉載請附上博文連結!