天天看點

深入了解java虛拟機(一)—jvm記憶體模型總結

 本猿2013年畢業,到現在已經有五年了,雖然一直從事java工作,但是一直是寫業務代碼,設計業務産品那種,工作節奏比較散漫,最近才深深的感覺到我的能力跟畢業一兩年的沒多少差别,剛好最近工作閑了下來,開始看别人的一些部落格,看了一些感悟,真的很受打擊,不信你們看看,原來不知不覺我已經淪為不思進取,不求上進的人了

http://www.zuoxiaolong.com/html/article_184.html#

https://blog.csdn.net/chenssy/article/details/53738264

最近開始瘋狂買書補救,看書如果不去總結,那麼理論的知識肯定過不了幾天就會忘掉,我打算重新開始寫部落格了,雖然我的文筆比較菜,總結能力也不強,不管了,自己寫的自己能看懂就好了

 第一篇就寫一寫java虛拟機記憶體模型,簡稱JMM的結構吧:

JVM記憶體模型主要分為以下幾個區域:

程式計數器,java虛拟機棧,本地方法棧,堆記憶體,方法區,運作時常量池

程式計數器

 程式計數器是線程私有的區域,很好了解嘛~,每個線程當然得有個計數器記錄目前執行到那個指令。占用的記憶體空間小,可以把它看成是目前線程所執行的位元組碼的行号訓示器。如果線程在執行Java方法,這個計數器記錄的是正在執行的虛拟機位元組碼指令位址;如果執行的是Native方法,這個計數器的值為空(Undefined)。此記憶體區域是唯一一個在Java虛拟機規範中沒有規定任何OutOfMemoryError情況的區域。(這段是抄别人的,原諒我自己表述會誤導人)

虛拟機棧

虛拟機棧也是線程私有的,就是一個線程會配置設定一個棧,用于存放基本類型,引用類型的棧幀

  1. 局部變量表的建立是在方法被執行的時候,随着棧幀的建立而建立。而且,局部變量表的大小在編譯時期就确定下來了,在建立的時候隻需配置設定事先規定好的大小即可。此外,在方法運作的過程中局部變量表的大小是不會發生改變的。
  2. Java虛拟機棧會出現兩種異常:StackOverFlowError和OutOfMemoryError。 

    a) StackOverFlowError: 

    若Java虛拟機棧的記憶體大小不允許動态擴充,那麼當線程請求棧的深度超過目前Java虛拟機棧的最大深度的時候,就抛出StackOverFlowError異常。 

    b) OutOfMemoryError: 

    若Java虛拟機棧的記憶體大小允許動态擴充,且當線程請求棧時記憶體用完了,無法再動态擴充了,此時抛出OutOfMemoryError異常。

  3. Java虛拟機棧也是線程私有的,每個線程都有各自的Java虛拟機棧,而且随着線程的建立而建立,随着線程的死亡而死亡。

注:StackOverFlowError和OutOfMemoryError的異同? 

StackOverFlowError表示目前線程申請的棧超過了事先定好的棧的最大深度,但記憶體空間可能還有很多。 

而OutOfMemoryError是指當線程申請棧時發現棧已經滿了,而且記憶體也全都用光了。

本地方法棧

本地方法棧與虛拟機棧 是比較類似的,都會抛出StackOverFlowError異常和OutOfMemoryError異常,本地方法棧是為本地方法Native建立的,在hotspot虛拟機中,本地方法棧與虛拟機棧是在同一區域,,,待補充

堆記憶體

這個區域就是jvm的倉庫,基本上大部分的對象都存儲在這個區域,而且這個區域是線程共享的,不像程式計數器或者虛拟機棧是線程唯一的,這個區域也是垃圾回收最活躍的場所,也最容易發生記憶體洩露,OOM的部分,一般虛拟機把這個區分去成 年輕代和老年代,年輕代一般是用完就回收的局部變量,老年代是逃過幾次GC回收,多次被引用的對象存放的區域。堆記憶體不足的時候,就是無法配置設定記憶體去建立對象,就會抛出OutOfMemoryError: java heap space ,這個時候說明堆記憶體不足了,需要檢查代碼是不是有大量對象生成,或者存在記憶體洩露,

通過調節 -Xms,-Xmx來調整堆的大小,前提是要根據實體機的實際記憶體來調整。

方法區

方法區是存儲類的class檔案内容和資料結構,靜态變量,常量,可以參考類加載器的加載過程。jvm加載class檔案時,會把class檔案的位元組流内容和檔案結構,轉換成方法區的資料結構和内容,類加載時會生産一個class對象作為外部調用類方法的入口,這是唯一存儲在方法區的對象吧。方法區有的地方又稱 “永久代”。方法區記憶體不夠用的時候也會報 java.lang.OutOfMemoryError: PermGen space 的錯誤。可以通過調節-XX:PermSize=64 M -XX:MaxPermSize=128 M 參數來調大方法區的記憶體。

運作時常量池

是存在方法區的一小塊區域,一般是存放類編譯的時候的常量或者符号引用,例如有些基本的資料就存儲在這裡

Byte,Short,Integer,Long,Character,Boolean 預設建立了數值在 -128-127區域的對應的緩存

Integer a = 127;

Integer b =127;

system.out.print(a==b)  ——> true

Integer a = 150;

Integer b =150;

system.out.print(a==b)  ——> false

直接記憶體

這個區域不在虛拟機的掌控範圍,比如實作NIO時會直接使用直接記憶體,具體的查資料好吧。

好吧,第一篇就寫到這裡,感覺自己真的好水,還是科班出身的,如果你跟我類似,工作了四五年,還是混在小公司,享受着朝九晚五,又有些想法的話,不如跟我一起對java有一個深入的學習,不管技術能提高多少,至少我們努力過。

最近在看幾本書,收貨确實挺大的,推薦一下:

java 并發程式設計實戰

深入了解java虛拟機

effectivjava

慢慢看吧,

不喜歡勿噴啊,這些大部分都是我靠腦子回憶的,有些細節還是翻書找的,今年開始java深入學習之路

下一篇繼續講jvm GC的内容