天天看點

jvm記憶體模型1.方法區2.堆3. 程式計數器4.java虛拟機棧5.本地方法棧

jvm記憶體模型可以分為 堆、方法區、虛拟機棧、本地方法棧、程式計數器五個區域。見下圖。

jvm記憶體模型1.方法區2.堆3. 程式計數器4.java虛拟機棧5.本地方法棧

方法區是各個線程共享的記憶體區域,用于存儲類的資訊、常量與靜态變量。

hotspot vm把方法區也稱為永久代,permanent space。永久代對垃圾回收沒有顯著影響。

-xx:permsize //永久代最小空間

-xx:maxpermsize //永久代最大空間

示例: -xx:permsize=100m -xx:maxpermsize

java.lang.outofmemoryerror:perm space

永久代記憶體溢出,調大記憶體即可。

堆通常是jvm記憶體中最大的一塊,用于盛放對象。

堆又可以分為新生代與老年代,見圖2-1.

jvm記憶體模型1.方法區2.堆3. 程式計數器4.java虛拟機棧5.本地方法棧

圖2-1 jvm堆與方法區的記憶體模型

permanent space為永久代空間;heap space為堆空間,它又分為新生代空間與老年代空間。

它又可以分為2部分——eden space與survivor spaces,後者包括s0與s1。

eden ['i:dən]

n. 伊甸園(《聖經》中亞當和夏娃最初居住的地方)

新建立的對象将放入eden space。

又可以分為 s0  (survivor 0) 與 s1(survivor 1)。

當eden區滿時,觸發一次minor gc。還存活的對象将被複制到s0,同時清空eden區域。

當eden區再次滿時,觸發一次minor gc。eden+s0(不管s0有沒有滿)還存活的對象将被複制到s1,同時清空eden+s0區域。

當eden區再次滿時,觸發一次minor gc。eden+s1(不管s1有沒有滿)還存活的對象将被複制到s0,同時清空eden+s1區域。

如此往複。。。

注意survivor from 與survivor to的概念和s0與s1的概念。

新生代采用的就是複制算法。當survivor from 記憶體用完,就将還活着的對象複制到另外一塊survivor to上面。複制算法不會産生記憶體碎片。

新生代gc也是需要stop the world的,通常為幾十毫秒。

在新生代中經曆了n次垃圾回收後仍然存活的對象,就會被放到老年代中。是以可以認為老年代中存放的都是一些生命周期較長的對象。

一個對象,每經曆一次gc(minor gc 或 major gc),年齡就加一歲。

-xx:maxtenuringthreshold=15

指定對象到達15歲時被移到old區。預設值為15。

需要注意的是,并不是年齡非得到達指定值後才會被移到老年代,jvm還有自己的一套規則,煩人。

-xx:+printtenuringdistribution

這個參數用于顯示每次minor gc時survivor區中各個年齡段的對象的大小。

-xmx

//最大堆記憶體

-xms

//最小堆記憶體

-xmn

//新生代記憶體

示例:-xms2048m -xmx5120m

-xx:survivorratio//新生代中,eden區域與survivor區域的比值。預設為8。

java.lang.outofmemoryerror:java heap space

堆溢出。

名為pc,program counter,是一個寄存器,存放該線程要執行的下一條語句的位置。

每個線程都有自己的pc,線程間不共享。

每個線程都有自己的java虛拟機棧,線程間不共享。

每當進入一個函數時,建立棧幀(即stack frame,内含局部變量與函數出口等資訊),入棧,函數執行完退出時,出棧。

-xss 

//每個線程的棧大小,預設為1m

示例: -xss 2m

java.lang.stackoverflowerror

棧溢出。預設情況下函數嵌套達到2000層是沒有問題的。可以認為調大棧空間。

每個線程都有自己的本地方法棧,線程間不共享。

與java虛拟機棧類似,服務于本地(native)代碼。