之前本身只是用java去編寫程序,沒有深刻了解過,空閒下來本身看看書,學習JVM相關知識,這也是自我深造學習。雖然如今網上有不少這方面的博文之類,可是我認爲我還有必要本身去整理寫一下,畢竟看得多不如本身多動手親自去寫一遍。html
JAVA程序的之因此可以實現一次編譯到處運行,得益於他強大的虛擬機,虛擬機會將編譯好的字節碼文件加載到虛擬機內存中,通過一系列的驗證以後,初始化,最後在卸載加載的class文件。平常咱們用的最多的就是Sun公司的HotSpot虛擬機,此外還有BEA 的JRockit虛擬機和IBM的J9虛擬機。java
閒話很少說,下面圖表是一個java虛擬機運行時數據區,圖片的來源於http://www.cnblogs.com/AloneSword/p/4262255.html算法
由圖表能夠看出方法去和堆區是虛擬機中線程共享的,虛擬機棧和本地方法區以及程序計數器是線程私有的。編程
程序計數器:數組
是一塊較小的內存空間,它的做用能夠看作是當前線程所執行本身嗎的行號指示器,在虛擬機的概念模型李,字節碼解釋器工做時就是經過改變這個計數器的值來選取下一條須要執行的字節碼指令,分支,循環,跳轉、異常處理、縣城恢復等基礎功能都須要依賴這個計數器去完成。
多線程
因爲Java虛擬機的多線程是經過線程輪流切換並分配處理器執行時間的方式實現,在任何一個肯定的時刻,一個處理器(對於多核處理器來講是一個內核)只會執行一條線程中的指令。所以,爲了線程都須要一個獨立的程序計數器,各條線程之間的計數器互不影響,獨立存儲,所以咱們把這類內存區域稱爲「線程私有」的內存區域。
編程語言
若線程正在執行一個java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址,若是執行的native方法(簡單地講,一個Native Method就是一個java調用非java代碼的接口。一個Native Method是這樣一個java的方法:該方法的實現由非java語言實現,好比C。這個特徵並不是java所特有,不少其它的編程語言都有這一機制,好比在C++中,你能夠用extern "C"告知C++編譯器去調用一個C的函數。),這個計數器的值就爲空,這塊區域是惟一一個在java虛擬機規範中沒有規定任何OutOfMemoryError的區域。
函數
JAVA虛擬機棧:學習
和程序計數器同樣,java虛擬機棧也是線程私有的。它的生命週期和線程相同。虛擬機棧中描述的是java方法執行的內存模型:每一個方法在執行的時候都會同時建立一個棧幀用於存儲局部變量表、操做數棧、動態連接、方法出口等信息,每個方法被調用到執行完成工程就對應這個一個棧幀在java虛擬機棧中從入棧道出棧的過程。
編碼
局部變量表:
局部變量表是一組變量值的存儲空間,用於存放方法參數和方法內部定義的局部變量。改空間的大小通常在java程序被編譯爲class文件的時候就會被肯定下來。
操做數棧:
顧名思義,他就是java程序在執行方法時候的一個操做數據的棧,是一個後入先出棧。同局部變量表內存空間大小同樣,該部分容量在編譯的時候已經肯定。操做棧中的每個元素能夠是任意的java數據類型,32位數據佔用的棧容量爲1,64位數據佔用的棧空間容量爲2.
當方法剛開始執行的時候,這個方法的操做數棧內是空的,在方法執行過程當中會有各類字節碼指令向操做數棧中寫入和提取內容,也是就入棧和出棧操做,例如在作數學運算就是經過操做數棧來進行的。
動態連接方法:
每一個棧幀中包含一個指向運行時常量池中該棧幀所屬方法的引用(運行時常量池是方法區中的一部分),持有該引用是爲了支持方法調用過程當中的動態連接。class文件中的常量池中存有大量的符號引用,字節碼中的方法調用指令就以常量池中指向方法的符號引用爲參數,這些符號引用一部分會在類加載階段或者第一次使用的時候轉化爲直接引用,另外一部分將在每一次的運行期間轉化爲直接引用,這部分稱爲動態連接。
返回地址:
當一個方法在執行後,有兩種方式退出方法,一種是執行引擎遇到任意一個方法返回的字節碼指令,這種方法的退出方式爲正常退出,另外一種是在執行過程當中遇到異常退出。可是不管採用哪一種方式退出,在方法退出以後,都須要返回到方法被調用的位置,程序才能繼續執行,方法返回的時候須要在棧幀中保存一些信息,用來幫助恢復他的上層方法的執行狀態。
本地方法棧:
本地方法棧和虛擬機棧發揮的做用相似,區別就是虛擬機棧執行java方法也就是字節碼服務,而本地方法棧執行的虛擬機用到Native方法服務。改區域也是線程私有的。
因爲sun公司的HotSpot虛擬機直接把本地方法棧和虛擬棧合二爲一,因此在設置該區域大小的時候能夠經過-Xss參數進行設置,該區域會拋出StackOverflowError和OutOfMemoryError異常。
JAVA堆:
該區域是java虛擬機管理的內存中最大的一塊,java堆是被全部線程共享的一塊內存區域,在虛擬機啓用時建立,該區域的惟一目的就是存放對象的實例,幾乎全部的對象實例都在這裏分配,這一點在java虛擬機規範中的描述是:全部的對象實例以及數組都要在該區域進行分配空間。
改取用能夠經過參數-Xms和-Xmx進行設置大小。
java堆是進行垃圾收集器管理的主要區域,所以不少時候被稱爲GC堆,因爲如今收集器基本採用的分代收集算法,所以java堆中還能夠細分爲新生代和老年代,新生代再細緻一點就是Eden空間,From Survivor空間和To Survivor空間,他們的分配比例通常是8:1:1,。該區域會拋出OutOfMemoryError異常。
方法區:
和java堆同樣,是線程共享的內存區域,它主要用於存放已被虛擬機加載的類信息,常量、靜態變量、即時編譯器編譯後的代碼等數據。雖然JAVA虛擬機規範把方法區描述爲堆的一個邏輯部分,可是它卻又一個別名非堆(Non-Heap)。
運行時常量池:
該區域也是方法區的一部分,它主要指的是在編譯期被肯定,並被保存在已編譯的class文件中的一些數據。除了包含類中定義的一些基本數據(int,long)和對象型(String,Integer)的常量值,還包含一些以文本形式出現的符號引用,好比1:類和接口的限定名,2:字段的名稱和描述符,3:方法的名稱和描述符。
虛擬機必須爲每一個裝載的類型維護一個常量池。常量池就是該類型用到的一個常量的有序集合,包括直接常量和其餘類型,字段,方法和符號引用。對於String常量,她的值存儲在常量池中,而JVM的常量池在內存中是以表的形式存在的,對於String類型,有一個固定長度的CONSTANT_String_info表存儲字符串的值。
常量池中的項目類型:CONSTANT_Utf8_info 標誌1,表明的是UTF-8編碼的額字符串;CONSTANT_Integer_info,標誌3,整型字面量;CONSTATN_Float_info,標誌4,浮點型字面量;
CONSTANT_Long_info,標誌5,表明Long類型的字面量;CONSTANT_Double_info,標誌6,表明雙精度浮點型字面量;CONSTANT_Class_info,標誌7,表明類和接口的符號引用;CONSTANT_String_info,標誌8,表明字符串類型字面量;CONSTANT_Fielderf_info,標誌9,表明字段的符號引用;CONSTANT_Methodref_info,標誌10,表明勒種方法的符號引用;CONSTANT_InterfaceMethodref_info,標誌11,表明接口中方法的符號引用;CONSTANT_NameAndType_info標誌12,表明字段或方法的部分符號引用。
對於在HotSpot虛擬機上開發和部署的程序開發者而言,不少人願意把它稱爲永久代(Permanent Generation),可是二者並不等價,僅僅是由於HotSpot虛擬機設計團隊選擇把Gc分代收集擴展到方法區。
該區域除了和java堆同樣不須要選擇連續的內存和能夠選擇固定大小或者可擴展外,還能夠選擇不實現垃圾收集。相對而言,垃圾收集行爲在該區域比較少,可是並不是數據進入該區域就會「永久」存在,這個區域的內存回收目標主要是針對常量池的回收和對類型的卸載。
根據java虛擬機規範,當方法區沒法知足內存分配需求的時候,將會拋出OutOfMemoryError異常。