您的位置:首頁>正文

初始jvm(一)——jvm記憶體區域與溢出

jvm記憶體區域與溢出為什麼學習jvm 木板原理, 最短的一塊板決定一個水的深度, 當一個系統垃圾收集成為瓶頸的時候, 那麼就需要你對jvm的瞭解掌握。 當一個系統出現記憶體溢出, 記憶體洩露的時候, 因為你懂jvm知識, 可以更加快速定位錯誤, 可以通過參數去合理設置各記憶體區域的記憶體容量。 因為你對jvm的認識, 寫代碼的時候會潛意識地讓你注意代碼品質, 可能你會說是那是小小的性能提升, 但是量變會導致質變的。

jvm記憶體區域jvm記憶體劃分 方法區虛擬機器棧本地方法棧堆程式計數器

程式計數器 當前執行緒所執行的位元組碼的行號指示器。

因為cpu的每個核心只能同時運行一個執行緒, 所以當一個執行緒執行完時間片後切換到另一個執行緒, 切換時為了能恢復到正確的執行位置, 所以需要程式計數器(學過計算機組成原理的應該比較熟悉)。 如果是執行緒執行的是一個java方法那麼此時計數器記錄的是正在執行的虛擬機器位元組碼指令的位址。 如果是nativ方法(非java代碼), 計數器值為空。

虛擬機器棧 java執行的記憶體模型, 棧由棧幀組成, 執行緒調用一個java方法時, 創建一個棧幀, 方法返回時, 棧幀彈出。 棧幀入棧出棧的過程就是方法開始結束的過程棧幀存儲區域變數區(存放基底資料型別資料, 物件指標),運算元棧(存放運算元,

比如加法運算的時候運算元棧取值, 計算後再壓入棧), 動態連結, 方法出口。

本地方法棧 和虛擬機器棧作用類似, 只不過服務物件不同, 本地方法服務物件是非java方法, 虛擬機器棧服務物件是java方法

方法區 存放類的資訊、常量、靜態變數等運行時常量池是方法區一部分, 主要存放字面量(如final修飾的變數)和符號引用量(編譯原理方面)

堆 存放物件, 物件要在堆上分配記憶體堆分為年輕代和年老代年輕代分為伊甸區(Eden space)和倖存者區(Survivor space)倖存區分為from和to空間

總結 jvm的記憶體區域劃分為程式計數器, 虛擬機器棧, 本地方法棧, 方法區, 堆。 程式計數器, 虛擬機器棧和本地方法棧都是執行緒獨享的, 而方法區和堆是執行緒共用的

溢出理清概念 作業系統分配給進程的記憶體是有限的,

而jvm的記憶體區域我們已經知道, 當我們設置好堆和方法區的最大容量後, 那麼剩下的記憶體將分配給虛擬機器棧和本地方法區和程式計數器(佔用記憶體少)。 兩種常見的溢出異常, 一種OutOfMemoryError(OOM),一種StackOverflowError。

各區溢出情況 堆溢出, 當我們創建的物件佔用的記憶體超過最大堆容量時候, 會拋出OOM本地方法棧和虛擬機器棧溢出:當請求的棧深度超過虛擬機器所允許的深度的時候會拋出棧溢出, 這種情況我們在使用遞迴出錯的時候經常遇到;還有就是出現OOM的情況, 我們知道分配給這兩個棧的記憶體是有限, 和執行緒數和執行緒的棧記憶體有關係, 那麼當我們其中任意一個過大的話,

都有可能造成OOM方法區和運行時常量池溢出:方法區存放類的資訊, 有時我們用的框架在動態代理的時候會動態生成CLASS, 這個時候有可能會出現方法區的OOM;而常量池溢出我們可以用String的intern方法(如果常量池沒有與字串相等的字串, 就將這個字串存入方法區)進行模擬。

設置各區的jvm參數 設置堆的最小值-Xms, 堆的最大值-Xmx設置永久代(jdk8之前用永久代來實現方法區)的最小值-XX:PermSize , 最大值-XX:MaxPermSize設置棧容量-Xss

延伸關於創建字串 String s2=new String("jiajun"); String s6=new String("jiajun"); System.out.println(s2==s6); 結果為false, 都存放在堆記憶體, 但是兩個地方。 String s6=new String("jiajun"); String s1="jiajun"; System.out.println(s1==s6); 結果為false, s6存放在堆當中, 而s1存放在常量池當中 String s1="jiajun"; String s7="jiajun"; System.out.println(s1==s7); 結果為true, 都是存放在常量池 String s4="jia"; String s5=s4+"jun"; String s1="jiajun"; System.out.println(s1==s5); 結果為false, 變數的值在運行的時候才確定, 所以此時s5實際上是new一個物件 String s3="jia"+"jun"; String s1="jiajun"; System.out.println(s1==s3); 結果為true, 此時s1 s3都是指向常量池一個string String s1="jiajun"; String s8=new String("jia")+"jun"; System.out.println(s1==s8); 結果為false,

此時s8同樣是new出來一個物件

我覺得分享是一種精神, 分享是我的樂趣所在, 不是說我覺得我講得一定是對的, 我講得可能很多是不對的, 但是我希望我講的東西是我人生的體驗和思考, 是給很多人反思, 也許給你一秒鐘、半秒鐘, 哪怕說一句話有點道理, 引發自己內心的感觸, 這就是我最大的價值。 (這是我喜歡的一句話, 也是我寫博客的初衷)

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示