Java程序在運行時,須要在內存中分配空間。爲了提升運行效率,就對數據進行了不一樣的空間劃分。由於每一片區域都有特定的數據處理方式和內存管理方式。html
具體分爲5種內存空間:java
程序計數器:保證線程切換後能恢復到原來的執行位置。算法
虛擬機棧:(棧內存)爲虛擬機執行java方法服務,方法被調用時,建立棧幀-數據結構
本地方法棧:爲虛擬機執行使用到的Native方法服務多線程
堆內存:存放全部new出來的東西post
方法區:存儲被虛擬機加載的類信息,常量,靜態常量,靜態方法等。url
運行時常量池(方法區的一部分).net
GC對他們的回收:線程
內存區域中的程序計數器、虛擬機棧、本地方法棧這3個區域隨着線程而生,線程而滅;棧中的棧幀隨着方法的進入和退出而有條件的執行出棧和入棧的操做。每一個棧幀中分配多少內存基本是在類結構肯定下來時就已知的。在這個區域不須要過多的考慮回收的問題,由於方法結束或者線程結束時,內存天然就跟着回收了。3d
GC回收的主要對象:Java堆和方法區
一個接口中的多個實現類須要的內存可能不一樣,一個方法中的多個分支須要的內存也可能不同,咱們只有在程序處於運行期間時才能知道會建立哪些對象,這部份內存的分配和回收都是動態的,GC關注的也是這部份內存。
1.程序計數器:(線程私有)
每隔線程擁有一個程序計數器,在線程建立時建立,指向嚇一跳指令的地址
執行本地方法時,其值爲undefined。
說的通俗一點,咱們知道,Java是支持多線程的,程序先去執行A線程,執行到一半而後去執行B線程,而後又跑去接着執行A線程,那程序是怎麼記住A線程已經執行到哪裏了呢?這就須要程序計數器了。所以,爲了線程切換後可以恢復到正確執行的位置,每條線程都有一個獨立的程序計數器,這塊屬於「線程私有」的內存。
2.Java虛擬機棧(線程私有)
每隔方法被調用的時候會建立一個棧幀,用於存儲局部變量表,操做棧,動態連接,方法出口等信息。局部變量表存放的是:編譯器可知的基本數據類型,對象引用類型。
每一個方法被調用直到執行完的過程,就對應着一個棧幀在虛擬機中從引入到出棧的過程。
在Java虛擬機中,對這個區域規定了兩種異常狀況:
(1)若是線程請求的棧深度太深,超出了虛擬機所容許的深度,就會出現StackOverFlowError(好比無線遞歸,由於每一層棧幀都會佔用必定空間,erXss規定了棧的最大空間,超出這個值就會報錯)
(2)虛擬機棧能夠動態擴展,若是擴展到沒法申請足夠的內存空間,會出現OOM(OutOfMemory)
3.本地方法棧:
(1)本地方法棧與java虛擬機棧作用戶很是類似,區別是:java虛擬機棧是爲虛擬機執行java方法服務的而本地方法棧則是爲虛擬機使用到Native方法服務。
(2)Java虛擬機沒有對本地方法棧的使用和數據結構作強制規定,Sun HotSpot虛擬機就把java虛擬機棧和本地方法棧合二爲一。
(3)本地方法棧也會拋出StackOverFlowError和OutOfMemoryError
4.Java堆:堆內存
(1)堆是Java虛擬機所管理的內存區域中罪的的一塊,java堆是被全部縣城共享的內存區域,在java虛擬機啓動時建立堆內存的惟一目的就是存放對象實例,幾乎全部的對象實例都在堆內存分配。
(2)堆是GC管理的主要區域,從垃圾回收的角度看,因爲如今的垃圾收集器都是採用的粉黛手機算法,所以java堆還能夠初步細分爲新生代和老年代。
(3)Java虛擬機規定,堆能夠處於物理上不連續的內存空間中,只要邏輯上連續的便可。在實現的既能夠是固定的,也能夠是動態擴展的。若是在堆內存沒有完成實力分配,而且對大小也沒法擴展,就會拋出OutOfMemoryError異常。
5.方法區(線程共享)
(1)用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼數據。
(2)Sun HotSpot虛擬機把方法區叫作永久帶(permanent Generation),方法區中最終要的部分是運行時常量池。
6.運行時常量池:
(1)運行時常量池是方法區的一部分,天然受到方法區內存的限制,當常量池沒法再申請到內存時就會拋出OutOfMemoryError異常。
參考:
1.java虛擬機詳解:http://www.cnblogs.com/smyhvae/p/4748392.html
2.java中的各類數據類型在內存中存儲的方式:https://blog.csdn.net/sinat_29255093/article/details/52556449