廢話少說先上圖:java
程序計數器(Program Counter Register),也有稱做爲PC寄存器。想必學過彙編語言的朋友對程序計數器這個概念並不陌生,在彙編語言中,程序計數器是指CPU中的寄存器,它保存的是程序當前執行的指令的地址(也能夠說保存下一條指令的所在存儲單元的地址),當CPU須要執行指令時,須要從程序計數器中獲得當前須要執行的指令所在存儲單元的地址,而後根據獲得的地址獲取到指令,在獲得指令以後,程序計數器便自動加1或者根據轉移指針獲得下一條指令的地址,如此循環,直至執行完全部的指令。程序員
雖然JVM中的程序計數器並不像彙編語言中的程序計數器同樣是物理概念上的CPU寄存器,可是JVM中的程序計數器的功能跟彙編語言中的程序計數器的功能在邏輯上是等同的,也就是說是用來指示 執行哪條指令的。數組
因爲在JVM中,多線程是經過線程輪流切換來得到CPU執行時間的,所以,在任一具體時刻,一個CPU的內核只會執行一條線程中的指令,所以,爲了可以使得每一個線程都在線程切換後可以恢復在切換以前的程序執行位置,每一個線程都須要有本身獨立的程序計數器,而且不能互相被幹擾,不然就會影響到程序的正常執行次序。所以,能夠這麼說,程序計數器是每一個線程所私有的。數據結構
在JVM規範中規定,若是線程執行的是非native方法,則程序計數器中保存的是當前須要執行的指令的地址;若是線程執行的是native方法,則程序計數器中的值是undefined。多線程
因爲程序計數器中存儲的數據所佔空間的大小不會隨程序的執行而發生改變,所以,對於程序計數器是不會發生內存溢出現象(OutOfMemory)的。函數
Java棧也稱做虛擬機棧(Java Vitual Machine Stack),也就是咱們經常所說的棧,跟C語言的數據段中的棧相似。事實上,Java棧是Java方法執行的內存模型。爲何這麼說呢?下面就來解釋一下其中的緣由。spa
Java棧中存放的是一個個的棧幀,每一個棧幀對應一個被調用的方法,在棧幀中包括局部變量表(Local Variables)、操做數棧(Operand Stack)、指向當前方法所屬的類的運行時常量池(運行時常量池的概念在方法區部分會談到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些額外的附加信息。當線程執行一個方法時,就會隨之建立一個對應的棧幀,並將創建的棧幀壓棧。當方法執行完畢以後,便會將棧幀出棧。所以可知,線程當前執行的方法所對應的棧幀一定位於Java棧的頂部。講到這裏,你們就應該會明白爲何 在 使用 遞歸方法的時候容易致使棧內存溢出的現象了以及爲何棧區的空間不用程序員去管理了(固然在Java中,程序員基本不用關係到內存分配和釋放的事情,由於Java有本身的垃圾回收機制),這部分空間的分配和釋放都是由系統自動實施的。對於全部的程序設計語言來講,棧這部分空間對程序員來講是不透明的。線程
下圖表示了一個Java棧的模型:設計
局部變量表,顧名思義,想必不用解釋你們應該明白它的做用了吧。就是用來存儲方法中的局部變量(包括在方法中聲明的非靜態變量以及函數形參)。對於基本數據類型的變量,則直接存儲它的值,對於引用類型的變量,則存的是指向對象的引用。局部變量表的大小在編譯器就能夠肯定其大小了,所以在程序執行期間局部變量表的大小是不會改變的。指針
操做數棧,想必學過數據結構中的棧的朋友想必對錶達式求值問題不會陌生,棧最典型的一個應用就是用來對錶達式求值。想一想一個線程執行方法的過程當中,實際上就是不斷執行語句的過程,而歸根到底就是進行計算的過程。所以能夠這麼說,程序中的全部計算過程都是在藉助於操做數棧來完成的。
指向運行時常量池的引用,由於在方法執行的過程當中有可能須要用到類中的常量,因此必需要有一個引用指向運行時常量。
方法返回地址,當一個方法執行完畢以後,要返回以前調用它的地方,所以在棧幀中必須保存一個方法返回地址。
因爲每一個線程正在執行的方法可能不一樣,所以每一個線程都會有一個本身的Java棧,互不干擾。
本地方法棧與Java棧的做用和原理很是類似。區別只不過是Java棧是爲執行Java方法服務的,而本地方法棧則是爲執行本地方法(Native Method)服務的。在JVM規範中,並無對本地方發展的具體實現方法以及數據結構做強制規定,虛擬機能夠自由實現它。在HotSopt虛擬機中直接就把本地方法棧和Java棧合二爲一。4.堆
在C語言中,堆這部分空間是惟一一個程序員能夠管理的內存區域。程序員能夠經過malloc函數和free函數在堆上申請和釋放空間。那麼在Java中是怎麼樣的呢?
Java中的堆是用來存儲對象自己的以及數組(固然,數組引用是存放在Java棧中的)。只不過和C語言中的不一樣,在Java中,程序員基本不用去關心空間釋放的問題,Java的垃圾回收機制會自動進行處理。所以這部分空間也是Java垃圾收集器管理的主要區域。另外,堆是被全部線程共享的,在JVM中只有一個堆。
在C語言中,堆這部分空間是惟一一個程序員能夠管理的內存區域。程序員能夠經過malloc函數和free函數在堆上申請和釋放空間。那麼在Java中是怎麼樣的呢?
Java中的堆是用來存儲對象自己的以及數組(固然,數組引用是存放在Java棧中的)。只不過和C語言中的不一樣,在Java中,程序員基本不用去關心空間釋放的問題,Java的垃圾回收機制會自動進行處理。所以這部分空間也是Java垃圾收集器管理的主要區域。另外,堆是被全部線程共享的,在JVM中只有一個堆。
方法區在JVM中也是一個很是重要的區域,它與堆同樣,是被線程共享的區域。在方法區中,存儲了每一個類的信息(包括類的名稱、方法信息、字段信息)、靜態變量、常量以及編譯器編譯後的代碼等。
在Class文件中除了類的字段、方法、接口等描述信息外,還有一項信息是常量池,用來存儲編譯期間生成的字面量和符號引用。
在方法區中有一個很是重要的部分就是運行時常量池,它是每個類或接口的常量池的運行時表示形式,在類和接口被加載到JVM後,對應的運行時常量池就被建立出來。固然並不是Class文件常量池中的內容才能進入運行時常量池,在運行期間也可將新的常量放入運行時常量池中,好比String的intern方法。
在JVM規範中,沒有強制要求方法區必須實現垃圾回收。不少人習慣將方法區稱爲「永久代」,是由於HotSpot虛擬機以永久代來實現方法區,從而JVM的垃圾收集器能夠像管理堆區同樣管理這部分區域,從而不須要專門爲這部分設計垃圾回收機制。不過自從JDK7以後,Hotspot虛擬機便將運行時常量池從永久代移除了。