JVM方面

簡述下雙親委派原則?

答:
1.概念: 如果一個類加載器收到了加載某個類的請求,則該類加載器并不會去加載該類,而是把這個請求委派給父類加載器,每一個層次的類加載器都是如此,因此所有的類加載請求最終都會傳送到頂端的啟動類加載器;只有當父類加載器在其搜索范圍內無法找到所需的類,并將該結果反饋給子類加載器,子類加載器會嘗試去自己加載怀樟。
代碼實現:

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
    {
        // 同步上鎖
        synchronized (getClassLoadingLock(name)) {
            // 先查看這個類是不是已經加載過
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // 遞歸,雙親委派的實現群发,先獲取父類加載器瘪贱,不為空則交給父類加載器
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    // 前面提到,bootstrap classloader的類加載器為null觅闽,通過find方法來獲得
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                }

                if (c == null) {
                    // 如果還是沒有獲得該類艘儒,調用findClass找到類
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // jvm統(tǒng)計
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            // 連接類
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

2. 需要的原因:
(1):如果不是同一個類加載器加載编丘,即時是相同的class文件,也會出現判斷不想同的情況彤悔,從而引發(fā)一些意想不到的情況嘉抓,為了保證相同的class文件,在使用的時候晕窑,是相同的對象抑片,jvm設計的時候,采用了雙親委派的方式來加載類杨赤。
(2):防止重復加載同一個.class敞斋。通過委托去向上面問一問,加載過了疾牲,就不用再加載一遍植捎。保證數據安全。
(3):防止官方自定義的類被覆蓋阳柔,因為在查看父類已經加載了某些類焰枢,那么就不會再次加載
3. 具體的加載器: jvm提供了三種系統(tǒng)加載器:

  1. 啟動類加載器(Bootstrap ClassLoader):C++實現,在java里無法獲取,負責加載<JAVA_HOME>/lib下的類济锄。
  2. 擴展類加載器(Extension ClassLoader): Java實現暑椰,可以在java里獲取,負責加載<JAVA_HOME>/lib/ext下的類荐绝。
  3. 系統(tǒng)類加載器/應用程序類加載器(Application ClassLoader):是與我們接觸對多的類加載器一汽,我們寫的代碼默認就是由它來加載,ClassLoader.getSystemClassLoader返回的就是它低滩。

4. 破壞雙親委派原則: (1)原因: 我們需要加載自定義的類召夹,比如下列例子

ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
  • 比如JNDI,JDBC恕沫,DriverManager是被根加載器加載的监憎,那么在加載時遇到以上代碼,會嘗試加載所有Driver的實現類昏兆,但是這些實現類基本都是第三方提供的,根據雙親委派原則妇穴,第三方的類不能被根加載器加載爬虱。
  • 比如Tomcat:我們知道,Tomcat是web容器腾它,那么一個web容器可能需要部署多個應用程序跑筝。不同的應用程序可能會依賴同一個第三方類庫的不同版本,但是不同版本的類庫中某一個類的全路徑名可能是一樣的瞒滴。如多個應用都要依賴hollis.jar曲梗,但是A應用需要依賴1.0.0版本,但是B應用需要依賴1.0.1版本妓忍。這兩個版本中都有一個類是com.hollis.Test.class虏两。如果采用默認的雙親委派類加載機制,那么是無法加載多個相同的類世剖。所以定罢,Tomcat破壞雙親委派原則,提供隔離的機制旁瘫,為每個web容器單獨提供一個WebAppClassLoader加載器祖凫。

oom和棧溢出分析?

答:
Java 虛擬機棧用來描述 Java 方法執(zhí)行的內存模型酬凳。線程創(chuàng)建時就會分配一個椈菘觯空間,線程結束后椖校空間被回收稠屠。
棧中元素用于支持虛擬機進行方法調用,每個方法在執(zhí)行時都會創(chuàng)建一個棧幀存儲方法的局部變量表、操作棧完箩、動態(tài)鏈接和返回地址等信息赐俗。

棧存的是分配給一個線程使用的,而堆是整個虛擬機使用的弊知,這兩個異常都是因為存的東西太多溢出了產生的異常阻逮,那么首先我們要分析他里面存的是什么,然后才能分析原因秩彤,如下叔扼。調整參數大小是最后步驟,我們要先排查是否有錯

虛擬機棧會產生兩類異常:

StackOverflowError: 線程請求的棧深度大于虛擬機允許的深度拋出漫雷。

  • 原因: JVM 線程棧存儲了方法的執(zhí)行過程瓜富、基本數據類型、局部變量降盹、對象指針和返回值等信息与柑,這些都需要消耗內存。一旦線程棧的大小增長超過了允許的內存限制蓄坏,就會拋出 java.lang.StackOverflowError 錯誤价捧。一般是因為遞歸錯誤,導致一直遞歸調用方法涡戳,如果是因為實際應用的話结蟋,可以通過調大JVM參數

OutOfMemoryError: 如果 JVM 棧容量可以動態(tài)擴展,虛擬機棧占用內存超出拋出渔彰。

  • 原因:
    1. java.lang.OutOfMemoryError:Java heap space(java堆內存溢出) 發(fā)生這種問題的原因是java虛擬機創(chuàng)建的對象太多嵌屎,在進行垃圾回收之間,虛擬機分配的到堆內存空間已經用滿了恍涂,與Heap space有關宝惰。堆大小可以通過虛擬機參數-Xms,-Xmx等修改(堆區(qū)域用來存放Class的實例(即對象)這里是new出來的)。
    2. java.lang.OutOfMemoryError: PermGen space(Java永久代(元數據)溢出再沧,即方法區(qū)溢出了)------>發(fā)生這種問題的原意是程序中使用了大量的jar或class掌测,使java虛擬機裝載類的空間不夠。此種情況可以通過更改方法區(qū)的大小來解決产园,使用類似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改汞斧。另外,過多的常量尤其是字符串也會導致方法區(qū)溢出什燕。(方法區(qū)用于存儲被虛擬機加載的類信息粘勒、常量、靜態(tài)變量等數據屎即。這里是編碼寫的Class)
    3. OutOfMemoryError:unable to create new native thread 這種錯誤在Java線程個數很多的情況下容易發(fā)生庙睡。

引用的幾種方式事富?

答:
1. 強引用: 強引用是在程序代碼之中普遍存在的引用賦值,類似Object o = new Object()這種引用關系乘陪。無論任何情況下统台,只要強引用關系還在,垃圾收集器就永遠不會回收掉被引用的對象啡邑。
2. 軟引用: 用來描述一些還有用但非必須的對象贱勃。只被軟引用關聯的對象,在系統(tǒng)要發(fā)生內存溢出異常前谤逼,會把這些對象列進回收范圍之中進行二次回收贵扰,如果這次回收還是沒有足夠的內存,才會拋出溢出異常流部。應用場景:做緩存(瀏覽器的后退按鈕)
3. 弱引用: 也是用來描述那些非必須對象戚绕,但它的強度比軟引用更弱一些,被弱引用關聯的對象只能生存到下一次垃圾收集發(fā)生為止枝冀。當垃圾收集器開始工作時舞丛,無論當前內存是否足夠,都會回收掉只被弱引用關聯的對象果漾。
4. 虛引用: 虛引用與軟引用和弱引用的一個區(qū)別在于:虛引用必須和引用隊列 (ReferenceQueue)聯合使用球切。當垃圾回收器準備回收一個對象時,如果發(fā)現它還有虛引用跨晴,就會在回收對象的內存之前欧聘,把這個虛引用加入到與之 關聯的引用隊列中片林。程序可以通過判斷引用隊列中是否已經加入了虛引用端盆,來了解被引用的對象是否將要被垃圾回收。如果程序發(fā)現某個虛引用已經被加入到引用隊列费封,那么就可以在所引用的對象的內存被回收之前采取必要的行動焕妙。

jvm內存區(qū)域?

答:
1弓摘、程序計數器: 執(zhí)行字節(jié)碼的行號指示器焚鹊,線程私有,沒有OOM

2韧献、Java虛擬機棧: 存局部變量表末患、棧幀,線程私有

3锤窑、本地方法棧: 虛擬機棧為虛擬機執(zhí)行 Java 方法 (也就是字節(jié)碼)服務璧针,而本地方法棧則為虛擬機使用到的 Native 方法服務。 在 HotSpot 虛擬機中和 Java 虛擬機棧合二為一渊啰。

4、Java堆: GC堆半哟,存放對象實例拍皮,所有線程共享

5、方法區(qū): 它用于存儲已被虛擬機加載的類信息哗讥、常量、靜態(tài)變量胞枕、即時編譯器編譯后的代碼等數據杆煞。以及常量池子

如何判斷對象是否是垃圾?

  • 引用計數法: 設置引用計數器曲稼,對象被引用計數器加 1索绪,引用失效時計數器減 1,如果計數器為 0 則被標記為垃圾贫悄。會存在對象間循環(huán)引用的問題瑞驱,導致內存泄漏,一般不使用這種方法窄坦。
//循環(huán)引用例子
public class ReferenceCountingGc {
    Object instance = null;
    public static void main(String[] args) {
        ReferenceCountingGc objA = new ReferenceCountingGc(); 1
        ReferenceCountingGc objB = new ReferenceCountingGc(); 1
        objA.instance = objB;2
        objB.instance = objA;2
        objA = null;1
        objB = null;1
//兩個對象到最后引用都是1唤反,但是都獲取不到了,所以導致內存泄漏了
    }
}
  • 可達性分析: 通過 GC Roots 的根對象作為起始節(jié)點鸭津,從這些節(jié)點開始彤侍,根據引用關系向下搜索,(也可以說是遍歷圖)如果某個對象沒有被搜到逆趋,則會被標記為垃圾盏阶。可作為 GC Roots 的對象包括虛擬機棧和本地方法棧中引用的對象闻书、類靜態(tài)屬性引用的對象名斟、常量引用的對象。

  • 可用做GCroot的對象:

    1. 虛擬機棧(棧幀中的本地變量表)中引用的對象
    2. 本地方法棧(Native 方法)中引用的對象
    3. 方法區(qū)中類靜態(tài)屬性引用的對象
    4. 方法區(qū)中常量引用的對象
    5. 所有被同步鎖持有的對象
  • 枚舉根節(jié)點的方式:
    在HotSpot的實現中魄眉,是使用一組稱為OOPMap的數據結構來達到這個目的的砰盐,首先在類加載完成的時候,HotSpot就把對象內什么偏移量上是什么類型的數據計算出來坑律,在JIT編譯過程中岩梳,也會在特定的位置記錄下棧和寄存器中哪些位置是引用。這樣晃择,GC在掃描的時候冀值,就可以根據OOPMap上記錄的信息準確定位到哪個區(qū)域中有對象的引用,這樣大大減少了通過逐個遍歷來找出對象引用的時間消耗宫屠。

垃圾回收的分代算法(垃圾收集算法及各自的優(yōu)缺點)列疗?

答:
1、標記-清除算法(老年代)

  • “標記-清除”算法是最基礎的算法激况,分為“標記”和“清除”兩個階段:首先標記出所有需要回收的對象作彤,在標記完成后統(tǒng)一回收掉所有被標記的對象膘魄。
  • 缺點:
  1. 執(zhí)行效率不穩(wěn)定;標記和清除兩個過程的執(zhí)行效率隨對象數量增長而降低竭讳。
  2. 內存空間的碎片化問題创葡;標記、清除之后會產生大量不連續(xù)的內存碎片绢慢,導致當需要分配較大對象時無法找到足夠的連續(xù)空間而不得不提前觸發(fā)另一次垃圾收集動作灿渴。

2、標記-復制算法(針對新生代)
標記-復制算法將可用內存按容量劃分為大小相等的兩塊胰舆,每次使用其中的一塊骚露。當這塊的內存用完了,就將還存活著的對象復制到另一塊上面缚窿,然后再把已使用過的內存空間一次清理掉棘幸。

  • 優(yōu)點:
  1. 分配內存時不用考慮空間碎片的復雜情況,只要移動堆頂指針倦零,按順序分配即可误续。
  • 缺點:
  1. 將可用內存縮小為了原來的一半,空間浪費多扫茅。

3蹋嵌、標記-整理算法(針對老年代)

復制算法在對象存活率較高時就需要執(zhí)行較多的復制操作,效率將會變低葫隙。更關鍵的是栽烂,如果不想浪費50%的空間,就需要有額外的空間進行分配擔保恋脚,以應對被使用的內存中所有對象都100%存活的極端情況腺办,所以在老年代一般不能直接選用復制算法。
根據老年代的特點提出了“標記-整理”算法慧起,標記過程仍然與“標記-清除”算法一樣菇晃,但后續(xù)步驟不是直接對可回收對象進行清理册倒,而是讓所有存活的對象都向空間一端移動蚓挤,然后直接清理掉邊界以外的內存。

標記-清除算法與標記-整理算法的本質差異在于前者是一種非移動式的回收算法驻子,而后者是移動式的灿意。是否移動對象都存在弊端,移動對象操作必須全程暫停用戶應用程序才能進行("Stop The World")崇呵,不移動對象會影響應用程序的吞吐量缤剧。

JDK1.8用的垃圾回收器?

CMS收集器是怎樣的域慷?

答:

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器荒辕,基于標記-清除算法實現汗销,是一款老年代收集器,它非常符合那些集中在互聯網站或者B/S系統(tǒng)的服務端上的Java應用抵窒,這些應用都非常重視服務的響應速度弛针。
整個工作流程包括四個步驟:
1. 初始標記: 僅僅標記GC Roots能直接關聯到的對象,速度很快李皇,需要“Stop The World”削茁。
2. 并發(fā)標記: 從GC Roots的直接關聯對象開始遍歷整個對象圖的過程,耗時較長但不需要停頓用戶線程掉房,可以與垃圾收集線程一起并發(fā)運行茧跋。
3. 重新標記: 修正并發(fā)標記期間因用戶程序繼續(xù)運作而導致標記產生變動的那一部分對象的標記記錄,需要“Stop The World”
4. 并發(fā)清除: 清理刪除標記階段判斷的已經死亡的對象卓囚,不需要移動存活對象瘾杭,可以與用戶線程同時并發(fā)。
由于整個過程中耗時最長的并發(fā)標記和并發(fā)清除過程收集器線程都可以與用戶線程一起工作哪亿,所以富寿,從總體上來說,CMS收集器的內存回收過程是與用戶線程一起并發(fā)執(zhí)行的锣夹。

優(yōu)點: 并發(fā)收集页徐、停頓低
缺點:

  • 對CPU資源敏感,總吞吐量會降低银萍。,因為在并發(fā)階段他雖然不會停頓用戶線程变勇,但是會因為占用一部分線程而導致應用線程變慢,降低吞吐量,如果應用程序負載本來就很高,好要分出一部分處理能力去執(zhí)行垃圾收集,就會導致應用的執(zhí)行速度大幅降低
  • 無法處理浮動垃圾。CMS在并發(fā)階段和并發(fā)清除階段由于用戶線程一直在運行贴唇,會導致新的對象產生,而此時垃圾收集已經結束搀绣,而這部分對象只能在下次被回收,而且還要預留部分內存空間給用戶線程使用,導致他并不能和其他垃圾收集器一樣戳气,等到老年代快滿的時候采取垃圾收集链患,而是在CMS是在達到68%的時候就會激活垃圾收集。
  • 標記-清除算法導致空間碎片

cms重新標記的時候三色算法了解嗎(并發(fā)標記的算法)瓶您?

答:三色標記法可以并發(fā)的原因麻捻,因為是并發(fā)標記的時候,是可能會線程切換的呀袱,那么這個時候為了恢復現場贸毕,你就需要保存足夠的信息,足以你恢復的時候去查看夜赵,假設這樣明棍,如果沒有三色標記法,那么只要你這個節(jié)點沒遍歷寇僧。

三色標記法的底層目的
三色標記法好處
三色標記算法
答:
三色標記法將對象的顏色分為了黑摊腋、灰沸版、白,三種顏色兴蒸。

  • 黑色: 該對象已經被標記過了推穷,且該對象下的屬性也全部都被標記過了。(程序所需要的對象)
  • 灰色: 該對象已經被標記過了类咧,但該對象下的屬性沒有全被標記完馒铃。(GC需要從此對象中去尋找垃圾)
  • 白色: 該對象沒有被標記過。(對象垃圾)

從我們main方法的根對象(JVM中稱為GC Root)開始沿著他們的對象向下查找痕惋,用黑灰白的規(guī)則区宇,標記出所有跟GC Root相連接的對象
掃描一遍結束后,一般需要進行一次短暫的STW(Stop The World)值戳,再次進行掃描议谷,此時因為黑色對象的屬性都也已經被標記過了,所以只需找出灰色對象并順著繼續(xù)往下標記(且因為大部分的標記工作已經在第一次并發(fā)的時候發(fā)生了堕虹,所以灰色對象數量會很少卧晓,標記時間也會短很多)
此時程序繼續(xù)執(zhí)行,GC線程掃描所有的內存赴捞,找出被標記為白色的對象(垃圾)清除

  • 問題:

1.錯標: 最開始A指向B逼裆,B指向D,但是在A完成標記(變成黑色)后赦政,遍歷到B胜宇,B指向D的引用消失(D訪問不到,會被標記為白色)恢着, 而A又指向了D(本應該重新被標記為黑色桐愉,但是因為A已經標記過,不會再次標記)掰派,此時因為A標記為黑色表示所有子對象都被標記从诲,所以D不會被檢測到,從而導致靡羡。此時GC線程繼續(xù)工作系洛,由于B不再引用D了,盡管A又引用了D亿眠,但是因為A已經標記為黑色碎罚,GC不會再遍歷A了磅废,所以D會被標記為白色纳像,最后被當做垃圾回收。
2. 漏標: 假設GC已經在遍歷對象B了拯勉,而此時用戶線程執(zhí)行了A.B=null的操作竟趾,切斷了A到B的引用憔购。

例子圖

本來執(zhí)行了A.B=null之后,B岔帽、D玫鸟、E都可以被回收了,但是由于B已經變?yōu)榛疑眨詴划斪龃婊顚ο笫浩^續(xù)遍歷下去。
最終的結果就是本輪GC不會回收B贾费、D钦购、E,留到下次GC時回收褂萧,也算是浮動垃圾的一部分押桃。

實際上,這個問題依然可以通過「寫屏障」來解決导犹,只要在A寫B(tài)的時候加入寫屏障唱凯,記錄下B被切斷的記錄,重新標記時可以再把他們標為白色即可谎痢。

G1 收集器(JDK9 默認垃圾收集器磕昼,可以收集老年代和新年代,采用了一種新的分區(qū))

參考鏈接
答:
以前垃圾回收器是 新生代 + 老年代节猿,用了CMS效果也不是很好掰烟,為了減少STW對系統(tǒng)的影響引入了G1(Garbage-First Garbage Collector),G1是一款面向服務端應用的垃圾收集器沐批。

G1 (Garbage-First) 是一款面向服務器的垃圾收集器,主要針對配備多顆處理器及大容量內存的機器. 以極高概率滿足 GC 停頓時間要求的同時,還具備高吞吐量性能特征.
它采用的是標記 - 壓縮算法纫骑,而且和 CMS 一樣都能夠在應用程序運行過程中并發(fā)地進行垃圾回收。G1 能夠針對每個細分的區(qū)域來進行垃圾回收九孩。在選擇進行垃圾回收的區(qū)域時先馆,它會優(yōu)先回收死亡對象較多的區(qū)域。這也是 G1 名字的由來躺彬。
被視為 JDK1.7 中 HotSpot 虛擬機的一個重要進化特征煤墙。它具備一下特點:

  • 并行與并發(fā): G1 能充分利用 CPU、多核環(huán)境下的硬件優(yōu)勢宪拥,使用多個 CPU(CPU 或者 CPU 核心)來縮短 Stop-The-World 停頓時間仿野。部分其他收集器原本需要停頓 Java 線程執(zhí)行的 GC 動作,G1 收集器仍然可以通過并發(fā)的方式讓 java 程序繼續(xù)執(zhí)行她君。
  • 分代收集: 雖然 G1 可以不需要其他收集器配合就能獨立管理整個 GC 堆脚作,但是還是保留了分代的概念。
  • 空間整合: 與 CMS 的“標記-清理”算法不同,G1 從整體來看是基于“標記-整理”算法實現的收集器球涛;從局部上來看是基于“標記-復制(相關的兩塊Region)”算法實現的劣针。
  • 可預測的停頓: 這是 G1 相對于 CMS 的另一個大優(yōu)勢,降低停頓時間是 G1 和 CMS 共同的關注點亿扁,但 G1 除了追求低停頓外捺典,還能建立可預測的停頓時間模型,能讓使用者明確指定在一個長度為 M 毫秒的時間片段內从祝。
  • G1 收集器的運作大致分為以下幾個步驟:
  1. 初始標記 (stop the world事件 CPU停頓只處理垃圾)襟己;標記GC Roots 可以直接關聯的對象,該階段需要線程停頓但是耗時短
  2. 并發(fā)標記 (與用戶線程并發(fā)執(zhí)行)牍陌;尋找存活的對象稀蟋,可以與其他程序并發(fā)執(zhí)行,耗時較長
  3. 最終標記 (stop the world事件 ,CPU停頓處理垃圾)呐赡;并發(fā)標記期間用戶程序會導致標記記錄產生變動(好比一個阿姨一邊清理垃圾退客,另一個人一邊扔垃圾)虛擬機會將這段時間的變化記錄在Remembered Set Logs 中。最終標記階段會向Remembered Set合并并發(fā)標記階段的變化链嘀。這個階段需要線程停頓萌狂,也可以并發(fā)執(zhí)行
  4. 篩選回收 (stop the world事件 根據用戶期望的GC停頓時間回收)。對每個Region的回收成本進行排序怀泊,按照用戶自定義的回收時間來制定回收計劃

SATB(snapshot-at-the-beginning): 上面global concurrent marking提到了STAB算法茫藏,那這個STAB到底為何物?STAB全稱為snapshot-at-the-beginning霹琼,其目的是了維持并發(fā)GC的正確性务傲。GC的正確性是保證存活的對象不被回收,換句話來說就是保證回收的都是垃圾枣申。如果標記過程是STW的話售葡,那GC的正確性是一定能保證的。但如果一邊標記忠藤,一邊應用在變更堆里面對象的引用挟伙,那么標記的正確性就不一定能保證了(并發(fā)標記使用的CMS算法,這里采用了STAB算法來防止漏標和錯標)模孩。
RememberedSet: G1 收集器使用的是化整為零的思想尖阔,把一塊大的內存劃分成很多個域( Region )。但問題是榨咐,難免有一個 Region 中的對象引用另一個 Region 中對象的情況介却。為了達到可以以 Region 為單位進行垃圾回收的目的, G1 收集器也使用了 RememberedSet 這種技術块茁。G1中每個Region都有一個與之對應的RememberedSet 齿坷,在各個 Region 上記錄自家的對象被外面對象引用的情況。當進行內存回收時,在GC根節(jié)點的枚舉范圍中加RememberedSet 即可保證不對全堆掃描也不會有遺漏胃夏。并加快掃描效率轴或。進行垃圾回收時昌跌,如果Region1有根對象A引用了Region2的對象B仰禀,顯然對象B是活的,如果沒有Rset蚕愤,就需要掃描整個Region1或者其它Region答恶,才能確定對象B是活躍的,有了Rset可以避免對整個堆進行掃描萍诱。

為了解決這個問題悬嗓,STAB的做法在GC開始時對內存進行一個對象圖的邏輯快照(snapshot),通過GC Roots tracing 參照并發(fā)標記的過程裕坊,只要被快照到對象是活的包竹,那在整個GC的過程中對象就被認定的是活的,即使該對象的引用稍后被修改或者刪除籍凝。同時新分配的對象也會被認為是活的周瞎,除此之外其它不可達的對象就被認為是死掉了。這樣STAB就保證了真正存活的對象不會被GC誤回收饵蒂,但同時也造成了某些可以被回收的對象逃過了GC声诸,導致了內存里面存在浮動的垃圾(float garbage)。

G1把Java內存拆分成多等份退盯,多個域(Region)彼乌,邏輯上存在新生代和老年代的概念,但是沒有嚴格區(qū)分渊迁。每一個Region慰照,它要么是young的,要么是old的琉朽。還有一類十分特殊的Humongous焚挠。所謂的Humongous,就是一個對象的大小超過了某一個閾值——HotSpot中是Region的1/2漓骚,那么它會被標記為Humongous蝌衔。如果我們審視HotSpot的其余的垃圾回收器,可以發(fā)現這種對象以前被稱為大對象蝌蹂,會被直接分配老年代噩斟。而在G1回收器中,則是做了特殊的處理孤个。

G1 收集器在后臺維護了一個優(yōu)先列表剃允,每次根據允許的收集時間,優(yōu)先選擇回收價值最大的 Region(這也就是它的名字 Garbage-First 的由來) 。這種使用 Region 劃分內存空間以及有優(yōu)先級的區(qū)域回收方式斥废,保證了 G1 收集器在有限時間內可以盡可能高的收集效率(把內存化整為零)椒楣。

一句話總結G1思維:每次選擇性的清理大部分垃圾來保證時效性跟系統(tǒng)的正常運行。
G1垃圾回收器詳解參考

CMS和G1的區(qū)別牡肉?

CMS 和G1 的區(qū)別 - 簡書 (jianshu.com)

簡述Java類加載機制捧灰?

  • 當需要某個類的時候,jvm會加載.class文件统锤,并創(chuàng)建對應的class對象毛俏,將class文件加載到虛擬機的內存,這個過程被稱為類的加載饲窿。

1. 加載: ClassLoader通過全類名查找類的字節(jié)碼文件并創(chuàng)建一個class對象
2. 驗證: 對文件格式煌寇,元數據,字節(jié)碼逾雄,符號引用等驗證正確性阀溶。
3. 準備: 為類變量(static修飾)分配內存并賦初始值:例子1、static int i = 5這里只是將i賦值為0鸦泳,初始化的階段再把i賦值為5银锻。2、不包含final修飾的static辽故,因為final在編譯的時候就已經分配了
4. 解析: 將符號引用(只是一段唯一標志目標的常量徒仓,目標可以是方法,接口誊垢,類)轉化為直接引用(目標真正的地址掉弛,也就是指針)。
5. 初始化: 如果該類有父類就對父類進行初始化

這里可以提一下雙親委派原則

Java對象的創(chuàng)建過程喂走?

答:

  1. 檢查該指令的參數能否在常量池中定位到一個類的符號引用殃饿,并檢查引用代表的類是否已被加載、解析和初始化芋肠,如果沒有就先執(zhí)行類加載乎芳。
  2. 通過檢查通過后虛擬機將為新生對象分配內存。
  3. 完成內存分配后虛擬機將成員變量設為零值
  4. 設置對象頭帖池,包括哈希碼奈惑、GC 信息、鎖信息睡汹、對象所屬類的類元信息等肴甸。
  5. 執(zhí)行 init 方法,初始化成員變量囚巴,執(zhí)行實例化代碼塊原在,調用類的構造方法友扰,并把堆內對象的首地址賦值給引用變量。

GC的主要區(qū)域庶柿?

答:
針對 HotSpot VM 的實現村怪,它里面的 GC 其實準確分類只有兩大種:

  • 部分收集 (Partial GC):
    1. 新生代收集(Minor GC / Young GC):只對新生代進行垃圾收集;
    2. 老年代收集(Major GC / Old GC):只對老年代進行垃圾收集浮庐。需要注意的是 Major GC 在有的語境中也用于指代整堆收集甚负;
    3. 混合收集(Mixed GC):對整個新生代和部分老年代進行垃圾收集。
  • 整堆收集 (Full GC): 收集整個 Java 堆和方法區(qū)兔辅。

Java的內存泄漏是什么?threadlocal為什么內存泄漏腊敲?

答:

  • 內存泄漏: 對象已經沒有被應用程序使用击喂,但是垃圾回收器沒辦法移除它們维苔,因為還在被引用著。
    在Java中懂昂,內存泄漏就是存在一些被分配的對象介时,這些對象有下面兩個特點,首先凌彬,這些對象是可達的沸柔,即在有向圖中,存在通路可以與其相連铲敛;其次褐澎,這些對象是無用的,即程序以后不會再使用這些對象伐蒋。如果對象滿足這兩個條件工三,這些對象就可以判定為Java中的內存泄漏,這些對象不會被GC所回收先鱼,然而它卻占用內存俭正。
  • threadlocal內存泄漏:
    ThreadLocalMap 中使用的 key 為 ThreadLocal 的弱引用,而 value 是強引用。所以焙畔,如果 ThreadLocal 沒有被外部強引用的情況下掸读,在垃圾回收的時候,key 會被清理掉宏多,而 value 不會被清理掉儿惫。這樣一來,ThreadLocalMap 中就會出現 key 為 null 的 Entry伸但。假如我們不做任何措施的話肾请,value 永遠無法被 GC 回收,這個時候就可能會產生內存泄露砌烁。ThreadLocalMap 實現中已經考慮了這種情況筐喳,在調用 set()催式、get()、remove() 方法的時候避归,會清理掉 key 為 null 的記錄荣月。使用完 ThreadLocal方法后 最好手動調用remove()方法

JVM內存結構和Java內存模型?

答:JVM內存結構指的是5個區(qū)域梳毙,Java內存模型是JMM哺窄。

簡述Parallel Scavenge和 Parallel Old 收集器(JDK8默認垃圾收集器)?

答:
ParNew :收集器其實就是 Serial 收集器(最簡單是收集器账锹,暫停程序萌业,收集垃圾,啟動程序)的多線程版本奸柬,除了使用多線程進行垃圾收集外生年,其余行為(控制參數、收集算法廓奕、回收策略等等)和 Serial 收集器完全一樣抱婉。新生代采用標記-復制算法,老年代采用標記-整理算法桌粉。它是許多運行在 Server 模式下的虛擬機的首要選擇蒸绩,除了 Serial 收集器外,只有它能與 CMS 收集器(真正意義上的并發(fā)收集器铃肯,后面會介紹到)配合工作患亿。
Parallel Scavenge:Parallel Scavenge 收集器關注點是吞吐量(高效率的利用 CPU)。CMS 等垃圾收集器的關注點更多的是用戶線程的停頓時間(提高用戶體驗)押逼。所謂吞吐量就是 CPU 中用于運行用戶代碼的時間與 CPU 總消耗時間的比值步藕。 Parallel Scavenge 收集器提供了很多參數供用戶找到最合適的停頓時間或最大吞吐量,如果對于收集器運作不太了解宴胧,手工優(yōu)化存在困難的時候漱抓,使用 Parallel Scavenge 收集器配合自適應調節(jié)策略,把內存管理優(yōu)化交給虛擬機去完成也是一個不錯的選擇恕齐。

GC流程(垃圾收集算法是思想乞娄,垃圾收集器是實現)?

答:核心思想就是根據各個年代的特點不同選用不同到垃圾收集算法(新生代用標記-復制显歧,老年代用標記-整理)仪或。
HotSpot JVM把年輕代分為了三部分:1個Eden區(qū)和2個Survivor區(qū)(分別叫from和to)。默認比例為8:1:1士骤。一般情況下范删,新創(chuàng)建的對象都會被分配到Eden區(qū)(一些大對象特殊處理),這些對象經過第一次Minor GC后拷肌,如果仍然存活到旦,將會被移到Survivor區(qū)旨巷。對象在Survivor區(qū)中每熬過一次Minor GC年齡就會增加1歲,當它的年齡增加到一定次數(默認15次)時添忘,就會被移動到年老代中采呐。年輕代的垃圾回收算法使用的是復制算法。

JVM常用的參數?

答:

  1. -Xms(最小) 和 -Xmx(最大):指定堆內存
  2. 設置垃圾回收器:
    Serial垃圾收集器(新生代)
    開啟:-XX:+UseSerialGC
    關閉:-XX:-UseSerialGC
    //新生代使用Serial 老年代則使用SerialOld

ParNew垃圾收集器(新生代)
開啟 -XX:+UseParNewGC
關閉 -XX:-UseParNewGC
//新生代使用功能ParNew 老年代則使用功能CMS

Parallel Scavenge收集器(新生代)
開啟 -XX:+UseParallelOldGC
關閉 -XX:-UseParallelOldGC
//新生代使用功能Parallel Scavenge 老年代將會使用Parallel Old收集器

ParallelOl垃圾收集器(老年代)
開啟 -XX:+UseParallelGC
關閉 -XX:-UseParallelGC
//新生代使用功能Parallel Scavenge 老年代將會使用Parallel Old收集器

CMS垃圾收集器(老年代)
開啟 -XX:+UseConcMarkSweepGC
關閉 -XX:-UseConcMarkSweepGC

G1垃圾收集器
開啟 -XX:+UseG1GC
關閉 -XX:-UseG1GC

  1. GC并行執(zhí)行線程數:-XX:ParallelGCThreads=16

G1出現主要是為了優(yōu)化CMS的哪些不足搁骑?

  1. CMS沒有采用復制算法斧吐,所以它不能壓縮,最終導致內存碎片化問題仲器。而G1采用了復制算法煤率,它通過把對象從若干個Region拷貝到新的Region過程中,執(zhí)行了壓縮處理乏冀。

  2. 在G1中蝶糯,堆是由Region組成的,因此碎片化問題比CMS肯定要少的多煤辨。而且裳涛,當碎片化出現的時候木张,它只影響特定的Region众辨,而不是影響整個堆中的老年代。

  3. 而且CMS必須掃描整個堆來確認存活對象舷礼,所以鹃彻,長時間停頓是非常常見的。而G1的停頓時間取決于收集的Region集合數量妻献,而不是整個堆的大小蛛株,所以相比起CMS,長時間停頓要少很多育拨,可控很多谨履。

美團CMS與G1分析

線上系統(tǒng)頻繁的進行 full gc,如何排查熬丧?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末笋粟,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子析蝴,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件博其,死亡現場離奇詭異模蜡,居然都是意外死亡,警方通過查閱死者的電腦和手機佑菩,發(fā)現死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門盾沫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來裁赠,“玉大人,你說我怎么就攤上這事赴精∽楹兀” “怎么了?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵祖娘,是天一觀的道長失尖。 經常有香客問我,道長渐苏,這世上最難降的妖魔是什么掀潮? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮琼富,結果婚禮上仪吧,老公的妹妹穿的比我還像新娘。我一直安慰自己鞠眉,他們只是感情好薯鼠,可當我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著械蹋,像睡著了一般出皇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哗戈,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天郊艘,我揣著相機與錄音,去河邊找鬼唯咬。 笑死纱注,一個胖子當著我的面吹牛,可吹牛的內容都是我干的胆胰。 我是一名探鬼主播狞贱,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蜀涨!你這毒婦竟也來了瞎嬉?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤勉盅,失蹤者是張志新(化名)和其女友劉穎佑颇,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體草娜,經...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡挑胸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了宰闰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茬贵。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡簿透,死狀恐怖,靈堂內的尸體忽然破棺而出解藻,到底是詐尸還是另有隱情老充,我是刑警寧澤,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布螟左,位于F島的核電站啡浊,受9級特大地震影響,放射性物質發(fā)生泄漏胶背。R本人自食惡果不足惜巷嚣,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望钳吟。 院中可真熱鬧廷粒,春花似錦、人聲如沸红且。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽暇番。三九已至嗤放,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奔誓,已是汗流浹背斤吐。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留厨喂,地道東北人。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓庄呈,卻偏偏與公主長得像蜕煌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子诬留,可洞房花燭夜當晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內容