1.JVM原理、java記憶體分析
目錄
JVM原理
JVM生命週期:一個執行中的Java虛擬機器有著一個清晰的任務:執行Java程式。你在同一臺機器上執行三個程式,就會有三個執行中的Java虛擬機器。
Main()方法是程式的起點,程式中其他的執行緒都由他來啟動。
- 每一個Java虛擬機器都包含方法區(method area)和堆(heap),所有執行緒共享。
- 當一個執行緒被建立時,會被分配只屬於他自己的PC暫存器“pc register”(程式計數器)和Java棧(Java stack)。在HotSopt虛擬機器中直接就把本地方法棧和Java棧合二為一。
JVM記憶體回收:Sun的JVMGenerationalCollecting(垃圾回收)原理是這樣的:把物件分為年青代(Young)、年老代(Tenured)、持久代(Perm),對不同生命週期的物件使用不同的演算法。(基於對物件生命週期分析)
垃圾回收器要回收物件的時候,首先要呼叫這個類的finalize()方法
通常我們說的JVM記憶體回收是在指堆記憶體回收,確實只有堆中的內容是動態申請分配的,所以以上物件的年輕代和年老代都是指的JVM的Heap空間,而持久代則是之前提到的MethodArea,不屬於Heap。
記憶體分析
共享
Java虛擬機器載入並解析一個類以後,將從類檔案中解析出來的資訊儲存與方法區
1.堆記憶體(heap):
儲存物件資料,提供所有類例項(new出的物件)和陣列物件儲存區域。堆中不存放基本型別和物件引用,只存放物件本身,jvm只有一個堆區,物件被使用完不會馬上消失,等待垃圾回收器不定時回收。
2.方法區(資料共享區/靜態區)(method):
方法區包含所有的class資訊、static變數、常量池。方法區中包含的都是在整個程式中永遠唯一的元素,如class,static變數。執行時常量池都分配在 Java 虛擬機器的方法區之中。隨著JVM的開啟而產生,在JVM結束時而消失的,生命週期和jvm一致。
2.1 常量池:
常量池指的是在編譯期被確定,並被儲存在已編譯的.class檔案中的一些資料。除了包含程式碼中所定義的各種基本型別(如int、long等等)和物件型(如String及陣列)的常量值(final)還包含一些以文字形式出現的符號引用,比如:
- 類和介面的全限定名
- 欄位的名稱和描述符
- 方法和名稱和描述符
如果是編譯期已經建立好(直接用雙引號定義的)的就儲存在常量池中,如果是執行期(new出來的)才能確定的就儲存在堆中。
獨有
PC暫存器中儲存執行緒執行的下一條指令。Java棧儲存了一個執行緒呼叫方法時的狀態,包括本地變數、呼叫方法的引數、返回值、處理的中間變數。
1.棧記憶體(stack)
每個執行緒都有自己獨有的一個棧區,出了作用域馬上消失釋放空間。
儲存區域性變數,只儲存基礎資料型別的物件和自定義物件的引用,基本資料型別(char,byte,short,int,long,float,double,boolean)的變數、引用資料型別(reference型別)
2.PC暫存器
建立字串記憶體分析:
字串常量池屬於方法區中的一塊。
String str = "hello" 這個語句會先檢查字串常量池是否存放這個"hello"這個字串物件,如果沒有存在,那麼就會在字串常量池中建立這個字串物件,如果存在直接返回該字串的記憶體地址值。
String str = new String("hello") 該語句會建立兩個物件:首先會先檢查字串常量池中存不存在"hello"這個字串物件,如果不存在就會建立,如果存在就不會建立。然後new String這個語句就會在堆記憶體中開闢一個字串物件,把字串常量池中的"hello"字串內容拷貝至堆記憶體中的字串物件,然後返回堆記憶體中字串物件的記憶體地址。總共兩個物件。