JVM調優推薦


posts - 233, comments - 205, trackbacks - 0

注意:本系列博客,主要參考自如下四本書html

《分佈式Java應用:基礎與實踐》《深刻理解Java虛擬機(第二版)》《深刻分析Java web技術內幕》《實戰java虛擬機》前端

一、爲何要了解JVM內存管理機制java

  • JVM自動的管理內存的分配與回收,這會在不知不覺中浪費不少內存,致使JVM花費不少時間去進行垃圾回收(GC)
  • 內存泄露,致使JVM內存最終不夠用

二、JVM內存結構linux

根據上圖,JVM內存結構包括:git

  • 方法區(也就是"持久代"),java8裏完全被移除,取而代之的是元數據區
  • 棧(在hotspot JVM中,JVM方法棧--Java虛擬棧,與本地方法棧是同一個)
  • PC寄存器(程序計數器)

還有一塊:web

  • 直接內存:直接向系統內存申請的一塊內存區域,javaNIO會使用,速度優於java堆內存。- 隸屬於物理內存,不屬於JVM內存

注意點:spring

  • 堆是GC的主要區域,方法區、直接內存也會發生GC
  • 棧與PC寄存器是每一個線程都會建立的私有區域,不會GC
  • 直接內存使用速度因爲堆內存,可是內存的申請速度低於堆內存

2.一、方法區docker

  • 存放內容(類的信息、類static屬性、方法、常量池)
    • 已經加載的類的信息(名稱、修飾符等)
    • 類中的static變量
    • 類中的field信息
    • 類中定義爲final常量
    • 類中的方法信息
    • 運行時常量池:編譯器生成的各類字面量和符號引用(編譯期)存儲在class文件的常量池中,這部份內容會在類加載以後進入運行時常量池,class文件的常量池查看 第三章 類文件結構與javap的使用
  • 使用實例:反射,在程序中經過Class對象調用getName等方法獲取信息數據時,這些信息數據來源於方法區。
  • 調節參數
    • -XX:PermSize:指定方法區的最小值,默認爲16M
    • -XX:MaxPermSize:指定方法區的最大值,默認爲64M
  • 所拋錯誤
    • 方法區域要使用的內存超過了其容許的大小時,拋出OutOfMemoryError
  • 內存回收的主要目標
    • 對類的卸載(這也是爲何不少企業使用velocity等模板引擎作前端而不是使用jsp的緣由之一)
    • 針對常量池的回收
  • 總結
    • 通常而言,在企業開發中,-XX:PermSize==-XX:MaxPermSize
    • 一般,這個大小設置爲256M就沒問題了,固然還要根據本身的程序去預估,並在運行過程當中去調整,這裏以在Resin服務器中配置爲例
      View Code
    • 類中的static變量會在方法區分配內存,可是類中的實例變量不會(類中的實例變量會隨着對象實例的建立一塊兒分配在堆中,固然如果基本數據類型的話,會隨着對象的建立直接壓入操做數棧)
    • 關於方法區的存放內容,能夠這樣去想全部的經過Class對象能夠反射獲取的都是從方法區獲取的(包括Class對象也是方法區的,Class是該類下全部其餘信息的訪問入口)

注意:常量池在jdk1.6在方法區;在jdk1.7在堆json

附:元數據區數組

  • 調節參數:-XX:MaxMetaspaceSize,若是不指定大小,極限狀況下可能耗盡系統全部內存
  • 元數據區是堆外的一塊直接內存

2.二、堆

  • 存放內容
    • 對象實例(類中的實例變量會隨着對象實例的建立一塊兒分配在堆中,固然如果基本數據類型的話,會隨着對象的建立直接壓入操做數棧),這一點查看 第四章 類加載機制
    • 數組值
  • 使用實例
    • 全部經過new建立的對象都在這塊兒內存分配,具體分配到年輕代仍是年老代須要根據配置參數而定(新建對象直接分配到年老代有兩種狀況,看下邊)
  • 調節參數
    • -Xmx:最大堆內存,默認爲物理內存的1/4但小於1G
    • -Xms:最小堆內存,默認爲物理內存的1/64但小於1G
    • -XX:MinHeapFreeRatio,默認當空餘堆內存小於最小堆內存的40%時,堆內存增大到-Xmx
    • -XX:MaxHeapFreeRatio,當空餘堆內存大於最大堆內存的70%時,堆內存減少到-Xms
  • 注意點
    • 在實際使用中,-Xmx與-Xms配置成相等的,這樣,堆內存就不會頻繁的進行調整了
  • 拋出錯誤
    • OutOfMemoryError:在堆中沒有內存完成實例分配(關於實例內存的分配,以後再說),此時堆內存已達到最大沒法擴展時。
  • 堆內存劃分

    • 新生代
      • 組成:Eden+From(S0)+To(S1)
      • -Xmn:整個新生代的大小
      • -XX:SurvivorRatio:調整Eden:From(To)的比率,默認爲8:1
    • 年老代
      • 新建對象直接分配到年老代,兩種狀況
        • 大對象:-XX:PretenureSizeThreshold(單位:字節)參數來指定大對象的標準,在Parallel Scavenge GC下可能無效,具體見《第五章 JVM垃圾收集器(1)
        • 大數組:數組中的元素沒有引用任何外部的對象
  • 總結
    • 企業開發中,-Xmx==-Xms
    • 一般,-Xmx設置爲2048m就沒問題了,固然還要根據本身的程序去預估,並在運行過程當中去調整,這裏以在Resin服務器中配置爲例
      View Code

      能夠看到,-Xms==-Xmx==2048m,年輕代大小-Xmn==512m,這樣,年老代大小就是2048-512==1536m,這個比率值得記住,在企業開發中,年輕代:年老代==1:3,而此時,咱們配置的-XX:MaxTenuringThreshold=15(這也是默認值),年輕代對象通過15次的複製後進入到年老代(關於這一點,在以後的GC機制中會說),

    • -XX:MaxTenuringThreshold與-XX:PretenureSizeThreshold不同,不要看錯

2.三、棧

  • 注意點
    • 每條線程都會分配一個棧,每一個棧中有多個棧幀(每個方法對應一個棧幀)
    • 線程建立的時候建立一個線程的java棧
    • 每一個方法在執行的同時都會建立一個棧幀,每一個棧幀用於存儲當前方法的局部變量表、操做數棧等,具體查看本文第一個圖,每個方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程,說的更明白一點,就是方法執行時建立棧幀,方法結束時釋放棧幀所佔內存
  • 存放內容
    • 局部變量表:八大基本數據類型數據、對象引用。該空間在編譯期已經分配好,運行期不變。
    • 操做數棧:是執行引擎直接操做的部分
  • 調節參數
    • -Xss:設置棧的大小,一般設置爲1m就好
      View Code
  • 支持native方法執行(本地方法棧)
  • 所拋錯誤
    • StackOverFlowError:線程請求的棧深度大於虛擬機所容許的深度。
      • 棧的深度就是方法調用嵌套的層數,受限於-Xss的大小
      • 典型場景:沒有終止條件的遞歸(遞歸基於棧)。
      • 每一個方法的棧的深度在javac編譯以後就已經肯定了,查看 第三章 類文件結構與javap的使用
    • OutOfMemoryError:虛擬機棧能夠動態擴展,若是擴展的時候沒法申請到足夠的內存。
      • 須要注意的是,棧能夠動態擴展,可是棧中的局部變量表不能夠。

2.四、PC寄存器(程序計數器)

  • 概念:當前線程所執行的字節碼的行號指示器,用於字節碼解釋器對字節碼指令的執行。
  • 多線程:經過線程輪流切換並分配處理器執行時間的方式來實現的,在任何一個時刻,一個處理器(也就是一個核)只能執行一條線程中的指令,爲了線程切換後能恢復到正確的執行位置,每條線程都要有一個獨立的程序計數器,各條線程之間計數器互不影響,獨立存儲。

附:對象分配(《實戰java虛擬機》)

posted on 2016-02-03 15:40 趙計剛 閱讀(2025) 評論(1) 編輯 收藏

FeedBack:
2018-03-09 19:06 | Tobin
贊,mark
暱稱: 趙計剛
園齡: 3年
粉絲: 572
關注: 22

< 2019年1月 >
30 31 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 1 2
3 4 5 6 7 8 9
Copyright ©2019 趙計剛 Powered By 博客園 模板提供: 滬江博客
相關文章
相關標籤/搜索