java虛擬機

Java虛擬機也就是我們通常說的JVM,學習Java就肯定要接觸Java虛擬機。以前在論壇上見過寫得好的博文,我摘錄了一部分,再配上一些自己的話就寫成了這個東西

編譯流程

JVM字節碼即為class文件,通過javac命令生成class文件,也就是說編譯是把源代碼裝換成class文件,而編譯最關鍵的地方在於編譯器對詞法、句法的分析

類加載器

其主要作用就是從class文件獲取信息,載入JVM內存,如圖:

java虛擬機

類加載器示意圖

JVM內存管理

按邏輯可分為4大部分:

1.Java棧(線程獨有): 主要作用是存放Java方法執行時的所有數據,由棧幀組成,一個幀代表一個方法的執行。每個方法從調用到執行完成就對應一個棧幀在虛擬機內的入棧到出棧

2.本地方法棧(線程獨有): 專門為native方法服務(如C、C++方法)

3.方法區(全局共享): 存儲被虛擬機加載的數據(如類信息、靜態變量)

4.堆區(全局共享): 所有new創建的對象內存都在堆中分配。堆內存分新生代和老生代,新生代存儲剛創建的對象。當內存不足時,虛擬機通過一系列算法將新生代移到老生代中,當新生代和老生代都滿了,會導致內存溢出(OOM)

內存管理分為內存分配和內存釋放,看一下上面的4個內存區域,可分為兩部分,一部分是 全局共享 ,一部分是 線程獨有

線程獨有的自然是隨線程啟動而啟動,隨線程銷燬而銷燬,這部分內存由JVM主動管理,沒GC什麼事

全局共享的就不一樣了,內存分配主要是由程序員顯式的使用new關鍵字來觸發的,至於new出來的這部分內存在哪分配,如何分配,是JAVA虛擬機來決定。而這部分內存的釋放,則是由GC來管理的

垃圾回收(GC)

垃圾回收主要針對堆內存

垃圾收集算法

引用計數法: 被引用1次計數器就加1,沒被引用時則被回收。假如兩個對象相互引用,則起不到作用。已廢棄

可達性算法(根搜索算法): 通過GC ROOT 對象開始搜索,回收不可達對象,存在強引用的寧可拋出OOM(內存溢出)也不會回收,弱引用會被回收

垃圾回收算法

標記—清除算法: 發現沒有引用的對象,直接回收,會導致內存碎片過多

複製算法: 搜索掃描沒有引用的對象,開闢新內存空間,將存活對象複製到新內存,舊內存直接清除,由於需多次交換內存空間,對象數量少時效率高,缺點是需要較大的內存空間

標記—整理算法: 在標記—清除算法的基礎上,清除掉不存活的對象後,把後面存活對象搬運過來,使內存連續,解決內存碎片問題

分代收集算法: 基於對對象生命週期分析後得出的垃圾回收算法。把對象分為年青代、年老代、持久代,對不同生命週期的對象使用不同的算法(上述方式中的一個)進行回收。垃圾回收器(從J2SE1.2開始)都是使用此算法的

1. Young(年輕代)

年輕代分三個區。一個Eden區,兩個 Survivor區。大部分對象在Eden區中生成。當Eden區滿時,還存活的對象將被複制到Survivor區(兩個中的一個),當這個 Survivor區滿時,此區的存活對象將被複制到另外一個Survivor區,當這個Survivor去也滿了的時候,從第一個Survivor區複製過來的並且此時還存活的對象,將被複制“年老區(Tenured)”。需要注意,Survivor的兩個區是對稱的,沒先後關係,所以同一個區中可能同時存在從Eden複製過來對象,和從前一個Survivor複製過來的對象,而複製到年老區的只有從第一個Survivor去過來的對象。而且,Survivor區總有一個是空的。

2. Tenured(年老代)

年老代存放從年輕代存活的對象。一般來說年老代存放的都是生命期較長的對象。

3. Perm(持久代)

用於存放靜態文件,如今Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者調用一些class

那麼何時觸發垃圾回收呢?當年輕代或老年代滿了,JVM無法為對象分配內存空間;調用System.gc(),但是請求不是命令,調不調用看虛擬機自身;程序運行時有一條低優先級GC程序

JVM、DVM和ART

由JVM又衍生出了DVM和ART,這裡也簡單介紹一下

DVM是基於JVM創造的,他執行dex文件而非class文件,類加載與JVM有較大區別,可同時存在多個DVM,JVM基於棧,DVM基於寄存器,尋址速度更快

ART可以認為是DVM的升級,ART採用了AOT預編譯技術,APP安裝時就完成了字節碼轉化為機器碼,執行速度更快了,但ART會佔用你更多的時間和空間,便利所帶來的副作用就是佔更多的時間和空間


分享到:


相關文章: