JVM中將內存分爲若干部分:堆、方法區、虛擬機棧、本地方法棧、程序計數器
程序計數器:該區域是內存中較小的一塊區域---是當前線程在執行的字節碼的行號指示器。程序計數器是線程私有的,每一個線程都有一個程序計數器,線程之間的程序計數器相互獨立,互不干擾。是java虛擬機規範中惟一一個沒有規定任何OutOfMemoryError狀況的區域
虛擬機棧:是線程私有的,其生命週期與線程是相同的。虛擬機棧描述的是java方法執行的內存模型,每一個方法在執行的時都會建立一個棧幀用於存儲局部變量表,操做數棧、動態連接、方法出口等信息。每一個方法從調用到結束就會有棧幀在虛擬機棧中入棧和出棧。一個方法的調用鏈可能會很長,因而當調用一個方法時,可能會有不少的方法都處於執行狀態,可是對於執行引擎來說,至於位於虛擬機棧棧頂的棧幀纔是有效的,這個棧幀被稱爲當前棧,這個棧幀所關聯的方法被稱爲當前方法,執行引擎的全部指令都是針對當前棧幀進行操做的。Stackoverflowerror異常(當線程申請的棧空間大於虛擬機所容許的深度時);outfmemoryError:當虛擬機棧沒法申請到足夠內存時。局部變量表是一組變量值的存儲空間,局部變量表的存儲單位是slot。若爲實例方法,則第0個slot是存儲的指向全部實例對象的引用,在方法中能夠經過this來訪問到這個隱含的參數;往下是參數,再往下是方法內的局部變量。對於操做數棧,在方法剛開始執行時操做數棧爲空,執行過程當中會有各類字節碼指令寫入或者談出。好比算法運算或者調用其餘方法時的參數等。動態連接:相似於與靜態連接即解析時符號引用轉化爲直接引用,動態連接是指在運行時轉化爲直接引用。
本地方法棧: 功能與虛擬機棧相同,只不過本地方法棧是爲native方法服務
堆:java堆是被線程共享的一塊區域。Java堆是用來存放實例對象以及數組對象。因爲如今有了逃逸分析技術,也能夠將對象分配在棧上。同時java堆也是垃圾回收的主要區域,垃圾回收主要採用分代回收,有年輕代,老年代。Java堆能夠是物理上不連續的區域,只要邏輯上連續便可。在堆中爲對象分配內存的分配方法有:碰撞指針(前提絕對規整,注意多線程同步問題,採用CAS原理加失敗重試實現或者本地線程分配緩衝)和空閒列表(不是規整的內存)方法,選擇哪種分配方法取決因而否規整,是否規整取決於採用的垃圾回收算法是否壓縮。對象的訪問通常有兩種方式:句柄和直接訪問。堆空間不足時拋出outOfMemoryError。
方法區:與堆同樣,是線程共享的的區域。用於存儲已經被虛擬機加載的類的類信息、常量、靜態變量、編譯後的代碼,運行時常量池(存儲編譯器生成的各類字面量與符號引用)等。方法區中有一個運行時常量池,class文件中的常量池在類被加載後就被放入運行時常量池。運行時常量池相對於class文件中的常量池,具備動態性。能夠在運行期間經過intern將常量放入池中,方法區空間不足時拋出outOfMemoryError。
在java虛擬機的規範以外還存在一個堆外內存,即直接內存。堆外內存能減小IO時的內存複製,實現零拷貝,不須要堆內存Buffer拷貝一份到直接內存,而後才寫入Socket中;並且也沒GC。
優勢:一、減小了垃圾回收的工做,由於垃圾回收會暫停其餘的工做(可能使用多線程或者時間片的方式,根本感受不到)
二、加快了複製的速度。由於堆內在flush到遠程時,會先複製到直接內存(非堆內存),而後在發送,而堆外內存至關於省略掉了這個工做。
缺點:一、堆外內存難以控制,若是內存泄漏,那麼很難排查
二、堆外內存相對來講,不適合存儲很複雜的對象。通常簡單的對象或者扁平化的比較適合。java