java 虛擬機(jī)(jvm)基本概念和虛擬機(jī)參數(shù)配置

  • 虛擬機(jī)大致分為系統(tǒng)虛擬機(jī)(vmware,可運行完整操作系統(tǒng)的軟件平臺)和程序虛擬機(jī)(jvm,專門為執(zhí)行當(dāng)個計算機(jī)程序而設(shè)計),在上面運行的軟件都被限制于虛擬機(jī)提供的資源中
  • 虛擬機(jī)的基本結(jié)構(gòu)
虛擬機(jī)基本結(jié)構(gòu).png

1.類加載子系統(tǒng):負(fù)責(zé)從文件系統(tǒng)或網(wǎng)絡(luò)中加載class信息,存放到方法區(qū),也就是一塊內(nèi)存空間

2.*方法區(qū):存放類信息,常量信息,常量池信息,包括字符串字面量和數(shù)字常量等

3.*java堆:jvm啟動的時候建立java堆,java程序最主要的內(nèi)存工作區(qū)域,幾乎所有的對象實例都放在java堆中,堆空間是所有線程共享的,

4.直接內(nèi)存:java的nio庫允許java程序使用直接內(nèi)存,從而提高性能,通常直接內(nèi)存速度會優(yōu)于java堆,讀寫頻繁的場合可能會考慮使用

5.*java棧:每個虛擬機(jī)線程都有一個私有的棧,線程棧在線程創(chuàng)建的時候被創(chuàng)建,線程棧中保存著局部變量,方法參數(shù),java的方法調(diào)用,返回值等等

6.本地方法棧和java棧非常類似 ,但是本地方法棧用于java調(diào)用本地方法(通常使用c編寫)

7.*java 自己的一套進(jìn)行垃圾清理的機(jī)制,稍后詳細(xì)說明

8.pc寄存器,每個線程的私有空間,jvm會為每個線程創(chuàng)建pc寄存器,在任意時刻,一個java線程總是在執(zhí)行一個方法,這個方法稱為當(dāng)前方法,如果當(dāng)前方法不是本地方法,pc寄存器就會執(zhí)行當(dāng)前正在被執(zhí)行的指令,如果是本地方法,pc寄存器值為undefined,pc寄存器存放如當(dāng)前執(zhí)行環(huán)境指針,程序計數(shù)器,操作棧指針,計算的變量指針等

9.*虛擬機(jī)最核心的組件,負(fù)責(zé)執(zhí)行虛擬機(jī)的字節(jié)碼,一般會先進(jìn)行編譯成機(jī)器碼后執(zhí)行

帶*的是重要部分

類加載之后一些信息(類信息,靜態(tài)信息被存放于方法區(qū)中,快永久區(qū)Perm)
類被實例化之后,被存儲到j(luò)ava堆中,一塊內(nèi)存空間
當(dāng)我們使用對象的時候,其實用的是這塊內(nèi)存空間的引用
這個引用存放在java棧中

image.png
  • java堆詳解
    • 幾乎所有的對象都放在其中,java堆是自動化管理的,通過垃圾回收機(jī)制,垃圾對象會自動清理,不需要顯示的釋放
    • 根據(jù)垃圾回收機(jī)制的不同,java堆可能會有不同的結(jié)構(gòu),最常見的是將整個java堆分為新生代和老年代,新生代存放新生的對象或者年齡不大的對象,老年代則存放老年對象
    • 新生代分為eden區(qū),s0區(qū),s1區(qū),s0和s1區(qū)也被稱為from和to區(qū)域,他們是倆塊大小相等并且可以互換角色的空間
    • 絕大多數(shù)情況下,對象首先分配在eden區(qū),在一次新生代回收后,如果對象還存活,則會進(jìn)入s0或者s1區(qū)(或者的原因是在任意時間s0和s1只能有一塊在使用),之后每經(jīng)過一次新生代回收,如果對象存活則它的年齡就加1,當(dāng)對象達(dá)到一定年齡(閾值)后,則進(jìn)入老年代(tenured區(qū),表明在一定考量后,這個數(shù)據(jù)一直被引用,老年區(qū)的數(shù)據(jù)不會被頻繁的回收,新生代則會被頻繁回收)
    • s0和s1區(qū)存在的意義在于,這倆塊區(qū)域的垃圾回收使用的是復(fù)制算法,核心思想是將內(nèi)存空間分為倆塊,每次只使用其中一塊,垃圾回收時,將正在使用的內(nèi)存中的存留對象復(fù)制到未被使用的內(nèi)存塊中去,之后去清除之前正在使用的內(nèi)存塊中的所有對象,反復(fù)去交換倆個內(nèi)存的角色,完成垃圾收集。
  • java 棧
    • 線程私有的內(nèi)存空間,一個棧一般有三部分組成:局部變量表,操作數(shù)棧和幀數(shù)據(jù)區(qū)
    • 局部變量表:用于保存函數(shù)的參數(shù)及局部變量
    • 操作數(shù)棧:主要保存計算過程的中間結(jié)果,同時作為計算過程中變量臨時的存儲空間
    • 幀數(shù)據(jù)區(qū):除了局部變量表和操作數(shù)棧之外,棧還需要一些數(shù)據(jù)來支持常量池的解析,幀數(shù)據(jù)區(qū)保存著常量池的指針,方便程序訪問常量池,此外,當(dāng)函數(shù)返回或者出現(xiàn)異常時,虛擬機(jī)必須有一個異常處理表,方便發(fā)送異常的時候找到異常的代碼,因此異常處理表也是幀數(shù)據(jù)區(qū)的一部分。
  • java方法區(qū)
    • 和堆一樣,方法區(qū)是一塊所有線程共享的內(nèi)存區(qū)域,它保存系統(tǒng)的類信息,比如類的字段,方法,常量池等,方法區(qū)的大小決定了系統(tǒng)可以保存多少個類,如果系統(tǒng)定義太多的類,導(dǎo)致方法區(qū)溢出。虛擬機(jī)同樣會拋出內(nèi)存溢出錯誤。方法區(qū)可以理解為永久區(qū)(Perm)
  • 虛擬機(jī)參數(shù)
    • 圍繞堆,棧,方法區(qū),垃圾回收機(jī)制 配置
    • 堆分配參數(shù):
      • -xx:+PrintGC 虛擬機(jī)啟動后,只要遇到GC就會打印日志
      • -xx:+UseSerialGC 配置串行回收器
      • -xx:+PrintGCDetails gc時可以查看詳細(xì)信息,包括各個區(qū)的情況
      • -Xms java程序啟動時初始堆大小
      • -Xmx java程序能獲得的最大堆大小
      • -Xmn 設(shè)置新生代大小,這個參數(shù)對gc有較大影響,一般設(shè)置為整個堆大小的三分之一到四分之一左右
      • -XX:SurvivorRatio 設(shè)置新生代中eden空間和from或to空間的比例,如果等于3,說明eden區(qū)比上from或to區(qū)為3:1
      • -XX:NewRatio 設(shè)置新生代和老年代的比例
      • -XX:+PrintCommandLineFlags 可以將虛擬機(jī)的參數(shù)輸出
      • 總結(jié),實際工作中可以將初始堆大小和最大堆大小設(shè)置相等,這樣可以減少程序運行時的垃圾回收次數(shù),從而提高性能
      • GCdetails解讀


        GCdetails
        • def new generation 新生代,分為eden區(qū),from區(qū),to區(qū),后面幾列是總空間,使用空間百分比,最后是內(nèi)存地址
        • tenured generation 老年代,后面幾列是總空間,使用空間百分比,最后是內(nèi)存地址
        • compacting perm gen 永久區(qū)(perm)
      • 堆溢出處理
        • 如果堆空間不足,則會拋出內(nèi)存溢出的錯誤(Out Of Memory,OOM),這類問題如果發(fā)生在生產(chǎn)環(huán)境,可能會引起嚴(yán)重的業(yè)務(wù)中斷.
        • -XX:HeapDumpOnOutOfMemoryError,使用該參數(shù)可以再內(nèi)存溢出時導(dǎo)出整個堆信息
        • -XX:HeapDumpPath 設(shè)置導(dǎo)出堆信息的存放路徑,與上面的參數(shù)配合使用
        • 例子:
          -Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/Test03.dump
        • dump文件分析工具
        • 分析方法
        • 代碼示例
        public static void main(String[] args) {
        
        //-Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/Test03.dump
        //堆內(nèi)存溢出
        Vector v = new Vector();
        for(int i=0; i < 5; i ++){
            v.add(new Byte[1*1024*1024]);
          }
        
        }
        
      • 棧參數(shù)配置
        • -Xss 指定單個線程的最大??臻g,??臻g的大小直接決定了函數(shù)可調(diào)用的最大深度
        • 代碼示例
        public class Test04 {
        
        //-Xss1m  
        //-Xss5m
        
        //棧調(diào)用深度
        private static int count;
        
        public static void recursion(){
            count++;
            recursion();
        }
        public static void main(String[] args){
            try {
                  recursion();
              } catch (Throwable t) {
          System.out.println("調(diào)用最大深入:" + count);
          t.printStackTrace();
            }
          }
        }
        
      • 方法區(qū)參數(shù)配置
        • 方法區(qū)保存系統(tǒng)的類信息
        • 默認(rèn)情況下,-XX:MaxPermSize 為64MB,如果系統(tǒng)運行時產(chǎn)生大量的類,就需要設(shè)置一個相對合適的方法區(qū),以免永久區(qū)內(nèi)存溢出的問題
        • -XX:PermSize 初始化方法區(qū)大小
        • -XX:MaxPermSize 方法區(qū)最大大小
      • 直接內(nèi)存參數(shù)配置
        • -XX:MaxDirectMemorySize,如果不設(shè)置,默認(rèn)值為最大堆空間,即-Xmx,直接內(nèi)存使用達(dá)到上限時,會觸發(fā)垃圾回收,如果不能有效的釋放空間,也會引起系統(tǒng)的OOM,
        • jdk1.7之后,不再關(guān)注這個參數(shù),配不配都沒什么大影響
  • Client和Server虛擬機(jī)工作模式
    • 只有在jdk1.7之前,jdk才分這倆個模式,1.7之后不再提供client模式,使用-client參數(shù)使用Client模式,使用-server使用Server模式,
    • 區(qū)別
      • Client模式啟動較快,適用于測試,不追求系統(tǒng)的長時間使用性能
      • Server模式啟動較慢,會對虛擬機(jī)的性能進(jìn)行負(fù)載的系統(tǒng)性能信息收集和使用更復(fù)雜的算法對程序進(jìn)行優(yōu)化,長期運行性能遠(yuǎn)遠(yuǎn)快于client模式
  • 關(guān)于jvm的博客參考
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容