初探JVM
JVM:Java虛擬機,有自己的處理器、堆棧、寄存器、指令系統,Java程序只需要生成在該虛擬機上運行的代碼就可以在多平臺上運行(屏蔽了操作系統相關的平臺信息)。
Java編譯器編譯.java文件 -> .class文件,Java虛擬機加載運行.class文件。
JVM運行時數據區域:
方法區:加載的類結構信息,常量值、字段、方法信息、靜態變量
Java虛擬機棧:屬于線程私有,方法調用的狀態,局部變量、參數、返回值、運算結果等
本地方法棧:可能會調用本地C棧,虛擬機會保持Java棧不變,不再在線程的Java棧中壓入新的幀,虛擬機只是簡單地動態連接并直接調用指定的本地方法
Java堆:對象實例,分配內存(GC主戰場)
程序計數器:保證程序能夠持續的運行(不會拋OutOfMemoryException),JVM的多線程是通過輪流切換、分配處理器來實現的,要保證切回來時繼續往下執行。
GC:垃圾回收機制
對象引用:
強引用:新建的對象為強引用時,GC絕對不會回收該類對象,寧愿拋OutOfMemoryException也不會回收
弱引用:不管內存是否足夠,GC只要執行就一定會回收該類對象
軟引用:當內存不夠時,GC會嘗試回收該類對象,如果回收后還是沒有足夠的內存,就會拋OutOfMemoryException
虛引用:如果一個對象僅持有虛引用,任何時候都可能會被GC回收,但是回收時會發一個系統通知(用來判斷GC在執行了)
垃圾標記算法:
引用計數算法:每個對象都有一個引用計數器,當對象每被引用一次就+1,引用失效一次就-1,計數=0表示可以被回收。
Obj o1 = new Obj();Obj o2 = o1;o1=null;此時o1計數仍為1,無法解決對象之間的相互引用。
根搜索算法:通過一系列的“GC Roots”的對象作為根節點,往下搜索組成引用鏈(遞歸),如果目標對象與根對象有引用鏈可達時,不會回收,如果沒有引用鏈不可達,則判定可回收。
垃圾收集算法:
標記-清除算法:根據根搜索算法標記可被回收的對象,然后對被標記為垃圾的對象進行回收。
缺陷:JVM會停止應用程序的運行并開啟GC線程進行根搜索標記,需要遍歷整個堆內存,效率很低,由于清理出來的空間是不連續的,不好給數組對象分配連續的內存空間,會產生大量內存碎片。
復制算法:先把內存一分為二,每次只使用其中一個區域,垃圾收集時,會把存活的對象全部連續的復制到另一個區域中,再對之前的區域全部回收。
缺陷:內存開銷少一半。
標記-壓縮算法:將存活的對象壓縮、排列到內存的一端,對端邊界以外的內存進行回收。
分代收集算法:Java堆內存存在的對象生命周期有很大的差別,有的很短有的很長,分代算法就是根據對象的生命周期長短將對象放到不同的周期區域中。Eden:From:To 8:1:1
在對象被創建時,會放到新生代Eden中,當Eden內存耗盡時,會執行一次GC將所有存活的對象復制到From中,然后繼續消耗Eden內存,下次執行GC,將Eden中所有存活的對象和From中的對象復制到To中,循環往復Eden+From->To / Eden+To->From,達到JVM內置的閥值后,會認為仍然存活的對象的生命周期很長,會放到老年代中,直到老年代中內存耗盡時GC會執行標記-壓縮算法回收垃圾。
內存泄漏/溢出/抖動
內存泄漏:一個不再被程序使用的對象或變量依舊存活在內存中無法被回收。內存泄漏越多,程序可使用的內存就越少。
內存溢出:程序申請內存時,沒有足夠的內存可供使用。
內存抖動:通常指在短時間內發生了多次內存的分配和釋放,主要原因就是短時間內頻繁創建對象,為了應對這種情況,JVM會頻繁觸發GC,而GC執行時其他線程會被掛起,頻繁GC,就會導致比如UI在繪制時會超過16ms一幀,造成畫面卡頓等。

浙公網安備 33010602011771號