1. 程式人生 > >Java中的內存劃分

Java中的內存劃分

內存空間 共享 對象實例 xss 擴展 們的 異常 over defined

Java程序在運行時,需要在內存中分配空間。為了提高運行效率,就對數據進行了不同的空間劃分。因為每一片區域都有特定的數據處理方式和內存管理方式。

技術分享

具體分為5種內存空間:

程序計數器:保證線程切換後能恢復到原來的執行位置。

虛擬機棧:(棧內存)為虛擬機執行java方法服務,方法被調用時,創建棧幀-

本地方法棧:為虛擬機執行使用到的Native方法服務

堆內存:存放所有new出來的東西

方法區:存儲被虛擬機加載的類信息,常量,靜態常量,靜態方法等。

運行時常量池(方法區的一部分)

GC對他們的回收:

內存區域中的程序計數器、虛擬機棧、本地方法棧這3個區域隨著線程而生,線程而滅;棧中的棧幀隨著方法的進入和退出而有條件的執行出棧和入棧的操作。每個棧幀中分配多少內存基本是在類結構確定下來時就已知的。在這個區域不需要過多的考慮回收的問題,因為方法結束或者線程結束時,內存自然就跟著回收了。

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異常。

可以參考http://www.cnblogs.com/smyhvae/p/4748392.html

Java中的內存劃分