ClassLoader類加載機制&&JVM內存管理

1、ClassLoader類加載機制java

在java中類加載是遵循委派雙親加載的:經過調用loadClass方法逐級往上傳遞委派加載請求,當找不到父ClassLoader時調用其findClass方法嘗試進行查找和加載,若是當前ClassLo找不所需的Class,則由其孩子嘗試進行查找和加載,若是當前ClassLoader找了所需的Class則將該Class按請求路徑逐級返回孩子。其關係圖以下所示:算法

ClassLoader.loadClass(...) 是ClassLoader的入口點。當一個類沒有指明用什麼加載器加載的時候,JVM默認採用AppClassLoader加載器加載沒有加載過的class,調用的方法的入口就是loadClass(...)。若是一個class被自定義的ClassLoader加載,那麼JVM也會調用這個自定義的ClassLoader.loadClass(...)方法來加載class內部引用的一些別的class文件。重載這個方法,能實現自定義加載class的方式,拋棄雙親委託機制若是要實現本身的類加載器,只需繼承ClassLoader,重寫findClass方法。多線程

2、內存管理併發

1.JVM內存模型spa

(1)方法區:存儲類的結構信息,類、類加載器元數據----永久代(堆的一部分),運行時常量池(每一個class運行時的常量表)存儲已被JVM加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據 —XX:PermSize、—XX:MaxPermSize線程

(2)堆:存放Java對象3d

(3)棧:執行引擎:執行一個個方法的串行流程,是線程。每當建立一個線程時爲其建立一個java棧和pc計數器,每調用一個方法則在棧中建立一個棧幀(保留方法的元信息:局部變量,返回地址等)對象

(4)本地方法棧:運行native方法的存儲空間blog

(5)靜態分配:編譯時已肯定(局部變量(含原始數據類型)、對象引用(指向對象在堆中的地址)),棧幀分配,方法結束則消失 繼承

(6)動態分配:程序執行時才肯定,建立java對象時在堆分配 可共享 方法結束不必定消失, 內存回收已對象再也不引用(直接或間接)爲前期

Java文件從源文件到在JVM執行的流程以下:

JAVA棧結構圖:

2.內存回收依據

判斷對象可回收的依據是對象再也不被引用,主要有兩種方法:

(1)計數法

給對象添加一個引用計數器,每當該對象被引用,它的計數器值就+1;當引用失效時,計數器就-1;在任何狀況下,當計數器值爲0時,就表示該對象再也不被使用

(2)可達性分析

只要改對象再也不被其餘活動對象引用就可回收,活動對象是指從gc根對象有路徑達到該對象。gc根對象即對象的引用

3.回收算法

(1)標記清除算法

首先標記出全部須要回收的對象,然後在標記完成後統一回收全部被標記的對象。存在.效率問題,標記和清除兩個過程的效率都不高; 空間碎片問題,標記清除後會產生大量不連續的內存碎片,空間碎片太多可能會致使之後在程序運行中須要分配較大對象時,沒法找到足夠的連續內存而不得不提早觸發另外一個垃圾回收動做。

(2)複製算法

將內存劃分爲相等的兩塊,每次只使用其中一塊。當這一塊內存用完時,就將還存活的對象複製到另外一塊上面,而後將已經使用過的內存空間一次清理掉。 

缺點:將內存縮小爲了原來的一半,對內存空間耗費較大。在對象存活率較高時,須要進行屢次複製操做,效率會變低。

(3)標記整理算法

不直接對可回收對象進行清理,而是讓全部存活對象都向另外一端移動,而後直接清理掉端邊界之外的內存。

(4)分代收集算法

把對象按照壽命長短進行分組,分爲新生代和老年代,而後根據各個年代的特色採用最適當的收集算法,在新生代採用複製算法,在老年代採用「標記-清除」或者「標記-整理」算法。

 

JVM將整個堆劃分爲Young區、Old區和Perm區,分別存放不一樣年齡的對象。

-Xms:堆起始大小

-Xmn:堆的最大大小,一般-Xms,-Xmn:設爲同樣大,避免後期的堆收縮

-XX:SurvivorRatio:新生代中Eden區域與Survivor區域的容量比值,默認爲8:1

-XX:PretenureSizeThreshold:新生代直接晉升到老年代的對象大小,大於這個參數的對象將直接在老年代分配

-XX:MaxTenuringThreshold:晉升到老年代的年齡。一個對象堅持過一次Minor GC後,年齡就增長1,當超過閥值就進入老年代

Young區分爲Eden區和兩個相同大小的Survivor區,其中全部新建立的對象都分配在Eden區域中,當Eden區域滿後會觸發minor GC 將Eden區仍然存活的對象複製到其中一個Survivor區域中,另一個Survivor區中的存活對象也複製到這個Survivor區域中,並始終保持一個Survivor區時空的。

Old區存放Young區Survivor滿後觸發minor GC後仍然存活的對象,當Eden區滿後會將存活的對象放入Survivor區域,若是Survivor區存不下這些對象,GC收集器就會將這些對象直接存放到Old區中,若是Survivor區中的對象足夠老,也直接存放到Old區中。若是Old區滿了,將會觸發Full GC回收整個堆內存。 

Perm區主要存放類的Class對象和常量,若是類不停地動態加載,也會致使Perm區滿。Perm區地垃圾回收也是有Full GC觸發地。

 

新建立的對象被分配在新生代,若是對象通過幾回回收後仍然存活,那麼就把這個對象劃分到老年代。老年代的收集頻度不象年輕代那麼頻繁,這樣就減小了每次垃圾回收所須要掃描的對象,從而提升了垃圾回收效率。

 

Serial收集器是一個單線程收集器,它進行垃圾收集時,必須暫停其餘全部的工做線程(Stop the world),直到它垃圾收集結束  client模式。 

ParNew收集器其實就是Serial收集器的多線程版本,在運行在Server模式下的虛擬機中,ParNew收集器是首選的新生代收集器。 

CMS收集器是一款併發收集器(用戶線程與垃圾收集線程同時執行),是一種以獲取最短回收停頓時間爲目標的收集器,它是基於標記-清除算法實現的初始標記、從新標記仍然須要"Stop the World",可是它們的速度都很快。初始標記只是標記一下GC Roots能直接關聯到的對象,從新標記是爲了修正併發標記期間由於用戶線程繼續運做而致使標記產生變更的那一部分對象的標記記錄。(初始標記→併發標記→從新標記→併發清除)

相關文章
相關標籤/搜索