天天看點

快速認識JVMJVM

JVM

什麼是JVM

JVM是java Virtual Machines,java虛拟機。java語言最大的特點:一次編譯,處處運作(Write Once,Run Anywhere)就是基于JVM來實作的。Java虛拟機中的Java解釋器負責将位元組碼檔案解釋成為特定的機器碼進行運作(可以了解為一個接口,然後不同的作業系統是不同的實作類),這個操作實作了一次編譯,處處運作。由于JVM是JRE的一部分,是以隻需要安裝JRE,我們的java程式就能在不同的作業系統上來運作。

JVM記憶體模型

快速認識JVMJVM

棧記憶體,存放8大基本類型資料,對象的引用,方法被調用的時候也會入棧,方法執行完後會出棧。

存放每個具體的對象,内部分為新生代、幸存代(from,to)、老年代、永久代(jdk1.8後稱為元空間)。

新生代,每個對象new出來的時候都在新生代,99%的對象被gc回收的時候也在新生代(因為沒有一直使用)。

新生代的對象每次被gc調用後,存活下來的對象就會進入幸存區,幸存區分為from和to兩個區域,并且會不斷交替轉化(誰空誰是to)的過程(gc之複制拷貝法)。

老年代,在經過一定次數的gc回收後仍然存活就進入老年代,可以通過JVM參數 “-XX:MaxTenuringThreshold”來設定,預設情況是15次。在老年代的對象,輕gc是作用不到的,必須要重gc才能回收老年代的對象。

在新生代中觸發輕gc,對象進入幸存區并進行from和to的區域及對象交換,如果幸存區已滿,則進入老年區。當老年代進行重gc的時候,會回收新生代,幸存區,老年代中所有可回收的對象,如果老年代也滿的情況下,下一次gc如果仍然沒有可回收的對象的話,則會觸發OOM(OutOfMemoryError)

方法區

定義上是一個特殊的堆,内部有一個運作時常量池,并且JVM在加載類的時候,也會給每一個類生成一個對應的class模闆,這個模闆對象也在這個方法區中。簡單來說,static,final修飾的會進入方法區,class模闆也在方法區,方法區内部還有一個運作時常量池。

方法區定義是在永久代中,永久代在jdk1.8以後也被稱為元空間,元空間用的不是JVM的記憶體,而是本地記憶體。

本地方法棧

本地方法棧是存放JAVA中本地方法的地方,JAVA中的本地方法就是被native修飾過的方法,他是JAVA無法作用的範圍,類似一個接口,接口去調用其他方法。不同的是,這個方法是由其他語言編寫的,JAVA最開始是基于C和C++寫的,他們希望JAVA能夠抛棄掉C和C++的缺點,是以一開始也被稱為C++ --,這邊調用的方法就是由C和C++來實作的。

程式計數器

又被稱為PC寄存器,是存放程式需要執行的下一條指令的位址。每個線程有自己的PC寄存器。

什麼是GC

GC全稱garbage collection,意味垃圾回收器,用于收集清除已經不需要再使用的對象,釋放記憶體空間。

GC算法

  • 引用計數法:對象初始化的時候給對象一個值來表示調用次數,每次調用就給該值+1,然後每次gc進行垃圾回收的時候,就根據每個對象的調用次數來判斷是否回收該對象。

    缺點:初始化的時候要給每個對象就建立一個值來表示調用次數,不僅耗時,而且浪費空間

  • 複制拷貝法:将記憶體空間二等分, 每次隻使用其中一塊. 當執行GC時, 将A部分的所有活動對象集體移到B中, 就可以将A全部釋放。(就是幸存區中的from區和to區的例子)

    缺點:在極端情況下,如果A區的空間全部塞滿了,那麼進行複制拷貝法的時候,就是将A的全部空間複制到B…

  • 标記清除法:在gc回收的時候,對所有需要存活的對象進行标記,标記完成後,對所有對象進行篩選,沒有被标記的直接被gc回收,有被标記的則存活下來。

    缺點:相當于要周遊2次所有對象,并且标記清除法釋放後的空間不是連續的

  • 标記壓縮法:在标記清除法的基礎上,讓存活下來的對象進行重新配置設定位址,保證記憶體空間連續

    缺點:比标記清除法更耗時

算法對比

效率:複制算法>标記清除法>标記壓縮法(此處的效率隻是簡單的對比時間複雜度,實際情況不一定如此)。

記憶體整齊度:複制算法=标記壓縮法>标記清除法。

記憶體使用率:标記壓縮法=标記清除法>複制算法。

GC算法優化

分代回收法:新生代和幸存代用複制算法,老年代用标記清除法+标記壓縮法(進行n次标記清除後,再進行1次标記壓縮法)

GC調優參數配置

-XX:MetaspaceSize=256m (元空間初始空間大小)

-XX:MaxMetaspaceSize=512m (元空間 最大空間,預設是沒有限制的。)

-Xms1024m (設定JVM初始為1024m)

-Xmx1024m (設定JVM最大記憶體1024m)

-Xmn512m (設定年輕代大小為512m)

-XX:+PrintGCDetails (輸出GC的詳細日志)

-XX:+PrintGCDateStamps (輸出GC的時間戳)

-Xloggc:/mnt/yyspace/logs/gc/system_gc.log (GC輸出路徑)

-XX:+UseGCLogFileRotation (啟用GC日志檔案的自動轉儲)

-XX:NumberOfGCLogFiles=3 (設定滾動日志檔案個數為)

-XX:GCLogFileSize=2048K (設定滾動日志檔案大小為)

-XX:+PrintStringTableStatistics 在JVM程序退出時,列印出StringTable的統計資訊到标準日志輸出目錄中

-XX:+HeapDumpOnOutOfMemoryError 可以讓JVM在出現記憶體溢出時候Dump出目前的記憶體轉儲快照。

-XX:HeapDumpPath=/mnt/yyspace/logs/heap/sys/(儲存快照的位址)

-Dcom.sun.management.jmxremote (以下參數為開啟遠端監控)

-Djava.rmi.server.hostname=10.1.1.186

-Dcom.sun.management.jmxremote.port=8999

-Dcom.sun.management.jmxremote.authenticate=false

-Dcom.sun.management.jmxremote.ssl=false

-Dcom.sun.management.jmxremote.local.only=false

OOM異常分析

-XX:+HeapDumpOnOutOfMemoryError 可以讓JVM在出現記憶體溢出時候Dump出目前的記憶體轉儲快照。

使用配置使得出現OOM的時候能夠dump出記憶體快照檔案,然後使用JProfiler來分析就可以了