最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

jvm原理之SystemGC源碼分析

 更新時(shí)間:2022年01月24日 12:11:20   作者:你假笨@JVM  
這篇文章主要介紹了jvm源碼分析之SystemGC的完全解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

概述

JVM的GC一般情況下是JVM本身根據(jù)一定的條件觸發(fā)的,不過我們還是可以做一些人為的觸發(fā),比如通過jvmti做強(qiáng)制GC,通過System.gc觸發(fā),還可以通過jmap來觸發(fā)等,針對(duì)每個(gè)場(chǎng)景其實(shí)我們都可以寫篇文章來做一個(gè)介紹,本文重點(diǎn)介紹下System.gc的原理

或許大家已經(jīng)知道如下相關(guān)的知識(shí)

  • system.gc其實(shí)是做一次full gc
  • system.gc會(huì)暫停整個(gè)進(jìn)程
  • system.gc一般情況下我們要禁掉,使用-XX:+DisableExplicitGC
  • system.gc在cms gc下我們通過-XX:+ExplicitGCInvokesConcurrent來做一次稍微高效點(diǎn)的GC(效果比Full GC要好些)
  • system.gc最常見的場(chǎng)景是RMI/NIO下的堆外內(nèi)存分配等

如果你已經(jīng)知道上面這些了其實(shí)也說明你對(duì)System.gc有過一定的了解,至少踩過一些坑,但是你是否更深層次地了解過它,比如

  • 為什么CMS GC下-XX:+ExplicitGCInvokesConcurrent這個(gè)參數(shù)加了之后會(huì)比真正的Full GC好?
  • 它如何做到暫停整個(gè)進(jìn)程?
  • 堆外內(nèi)存分配為什么有時(shí)候要配合System.gc?

如果你上面這些疑惑也都知道,那說明你很懂System.gc了,那么接下來的文字你可以不用看啦

JDK里的System.gc的實(shí)現(xiàn)

先貼段代碼吧(java.lang.System)

/**
 * Runs the garbage collector.
 * <p>
 * Calling the <code>gc</code> method suggests that the Java Virtual
 * Machine expend effort toward recycling unused objects in order to
 * make the memory they currently occupy available for quick reuse.
 * When control returns from the method call, the Java Virtual
 * Machine has made a best effort to reclaim space from all discarded
 * objects.
 * <p>
 * The call <code>System.gc()</code> is effectively equivalent to the
 * call:
 * <blockquote><pre>
 * Runtime.getRuntime().gc()
 * </pre></blockquote>
 *
 * @see     java.lang.Runtime#gc()
 */
public static void gc() {
    Runtime.getRuntime().gc();
}

發(fā)現(xiàn)主要調(diào)用的是Runtime里的gc方法(java.lang.Runtime)

/**
 * Runs the garbage collector.
 * Calling this method suggests that the Java virtual machine expend
 * effort toward recycling unused objects in order to make the memory
 * they currently occupy available for quick reuse. When control
 * returns from the method call, the virtual machine has made
 * its best effort to recycle all discarded objects.
 * <p>
 * The name <code>gc</code> stands for "garbage
 * collector". The virtual machine performs this recycling
 * process automatically as needed, in a separate thread, even if the
 * <code>gc</code> method is not invoked explicitly.
 * <p>
 * The method {@link System#gc()} is the conventional and convenient
 * means of invoking this method.
 */
public native void gc();

這里看到gc方法是native的,在java層面只能到此結(jié)束了,代碼只有這么多,要了解更多,可以看方法上面的注釋,不過我們需要更深層次地來了解其實(shí)現(xiàn),那還是準(zhǔn)備好進(jìn)入到j(luò)vm里去看看

Hotspot里System.gc的實(shí)現(xiàn)

如何找到native里的實(shí)現(xiàn)

上面提到了Runtime.gc是一個(gè)本地方法,那需要先在jvm里找到對(duì)應(yīng)的實(shí)現(xiàn),這里稍微提一下jvm里native方法最常見的也是最簡(jiǎn)單的查找,jdk里一般含有native方法的類,一般都會(huì)有一個(gè)對(duì)應(yīng)的c文件,比如上面的java.lang.Runtime這個(gè)類,會(huì)有一個(gè)Runtime.c的文件和它對(duì)應(yīng),native方法的具體實(shí)現(xiàn)都在里面了,如果你有source,可能會(huì)猜到和下面的方法對(duì)應(yīng)

JNIEXPORT void JNICALL
Java_java_lang_Runtime_gc(JNIEnv *env, jobject this)
{
    JVM_GC();
}

其實(shí)沒錯(cuò)的,就是這個(gè)方法,jvm要查找到這個(gè)native方法其實(shí)很簡(jiǎn)單的,看方法名可能也猜到規(guī)則了,Java_pkgName_className_methodName,其中pkgName里的".“替換成”_“,這樣就能找到了,當(dāng)然規(guī)則不僅僅只有這么一個(gè),還有其他的,這里不細(xì)說了,有機(jī)會(huì)寫篇文章詳細(xì)介紹下其中細(xì)節(jié)

DisableExplicitGC參數(shù)

上面的方法里是調(diào)用JVM_GC(),實(shí)現(xiàn)如下

JVM_ENTRY_NO_ENV(void, JVM_GC(void))
  JVMWrapper("JVM_GC");
  if (!DisableExplicitGC) {
    Universe::heap()->collect(GCCause::_java_lang_system_gc);
  }
JVM_END

看到這里我們已經(jīng)解釋其中一個(gè)疑惑了,就是DisableExplicitGC這個(gè)參數(shù)是在哪里生效的,起的什么作用,如果這個(gè)參數(shù)設(shè)置為true的話,那么將直接跳過下面的邏輯,我們通過-XX:+ DisableExplicitGC就是將這個(gè)屬性設(shè)置為true,而這個(gè)屬性默認(rèn)情況下是true還是false呢

product(bool, DisableExplicitGC, false,                                   
          "Tells whether calling System.gc() does a full GC")    

ExplicitGCInvokesConcurrent參數(shù)

這里主要針對(duì)CMSGC下來做分析,所以我們上面看到調(diào)用了heap的collect方法,我們找到對(duì)應(yīng)的邏輯

void GenCollectedHeap::collect(GCCause::Cause cause) {
  if (should_do_concurrent_full_gc(cause)) {
#ifndef SERIALGC
    // mostly concurrent full collection
    collect_mostly_concurrent(cause);
#else  // SERIALGC
    ShouldNotReachHere();
#endif // SERIALGC
  } else {
#ifdef ASSERT
    if (cause == GCCause::_scavenge_alot) {
      // minor collection only
      collect(cause, 0);
    } else {
      // Stop-the-world full collection
      collect(cause, n_gens() - 1);
    }
#else
    // Stop-the-world full collection
    collect(cause, n_gens() - 1);
#endif
  }
}

bool GenCollectedHeap::should_do_concurrent_full_gc(GCCause::Cause cause) {
  return UseConcMarkSweepGC &&
         ((cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) ||
          (cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent));
}

collect里一開頭就有個(gè)判斷,如果should_do_concurrent_full_gc返回true,那會(huì)執(zhí)行collect_mostly_concurrent做并行的回收

其中should_do_concurrent_full_gc中的邏輯是如果使用CMS GC,并且是system gc且ExplicitGCInvokesConcurrent==true,那就做并行full gc,當(dāng)我們?cè)O(shè)置-XX:+ ExplicitGCInvokesConcurrent的時(shí)候,就意味著應(yīng)該做并行Full GC了,不過要注意千萬不要設(shè)置-XX:+DisableExplicitGC,不然走不到這個(gè)邏輯里來了

并行Full GC相對(duì)正常的Full GC效率高在哪里

stop the world

說到GC,這里要先提到VMThread,在jvm里有這么一個(gè)線程不斷輪詢它的隊(duì)列,這個(gè)隊(duì)列里主要是存一些VM_operation的動(dòng)作,比如最常見的就是內(nèi)存分配失敗要求做GC操作的請(qǐng)求等,在對(duì)gc這些操作執(zhí)行的時(shí)候會(huì)先將其他業(yè)務(wù)線程都進(jìn)入到安全點(diǎn),也就是這些線程從此不再執(zhí)行任何字節(jié)碼指令,只有當(dāng)出了安全點(diǎn)的時(shí)候才讓他們繼續(xù)執(zhí)行原來的指令,因此這其實(shí)就是我們說的stop the world(STW),整個(gè)進(jìn)程相當(dāng)于靜止了

CMS GC

這里必須提到CMS GC,因?yàn)檫@是解釋并行Full GC和正常Full GC的關(guān)鍵所在,CMS GC我們分為兩種模式background和foreground,其中background顧名思義是在后臺(tái)做的,也就是可以不影響正常的業(yè)務(wù)線程跑,觸發(fā)條件比如說old的內(nèi)存占比超過多少的時(shí)候就可能觸發(fā)一次background式的cms gc,這個(gè)過程會(huì)經(jīng)歷CMS GC的所有階段,該暫停的暫停,該并行的并行,效率相對(duì)來說還比較高,畢竟有和業(yè)務(wù)線程并行的gc階段;而foreground則不然,它發(fā)生的場(chǎng)景比如業(yè)務(wù)線程請(qǐng)求分配內(nèi)存,但是內(nèi)存不夠了,于是可能觸發(fā)一次cms gc,這個(gè)過程就必須是要等內(nèi)存分配到了線程才能繼續(xù)往下面走的,因此整個(gè)過程必須是STW的,因此CMS GC整個(gè)過程都是暫停應(yīng)用的,但是為了提高效率,它并不是每個(gè)階段都會(huì)走的,只走其中一些階段,這些省下來的階段主要是并行階段,Precleaning、AbortablePreclean,Resizing這幾個(gè)階段都不會(huì)經(jīng)歷,其中sweep階段是同步的,但不管怎么說如果走了類似foreground的cms gc,那么整個(gè)過程業(yè)務(wù)線程都是不可用的,效率會(huì)影響挺大。CMS GC具體的過程后面再寫文章詳細(xì)說,其過程確實(shí)非常復(fù)雜的

正常的Full GC

正常的Full GC其實(shí)是整個(gè)gc過程包括ygc和cms gc(這里說的是真正意義上的Full GC,還有些場(chǎng)景雖然調(diào)用Full GC的接口,但是并不會(huì)都做,有些時(shí)候只做ygc,有些時(shí)候只做cms gc)都是由VMThread來執(zhí)行的,因此整個(gè)時(shí)間是ygc+cms gc的時(shí)間之和,其中CMS GC是上面提到的foreground式的,因此整個(gè)過程會(huì)比較長(zhǎng),也是我們要避免的

并行的Full GC

并行Full GC也通樣會(huì)做YGC和CMS GC,但是效率高就搞在CMS GC是走的background的,整個(gè)暫停的過程主要是YGC+CMS_initMark+CMS_remark幾個(gè)階段

堆外內(nèi)存常配合使用System GC

這里說的堆外內(nèi)存主要針對(duì)java.nio.DirectByteBuffer,這些對(duì)象的創(chuàng)建過程會(huì)通過Unsafe接口直接通過os::malloc來分配內(nèi)存,然后將內(nèi)存的起始地址和大小存到j(luò)ava.nio.DirectByteBuffer對(duì)象里,這樣就可以直接操作這些內(nèi)存。這些內(nèi)存只有在DirectByteBuffer回收掉之后才有機(jī)會(huì)被回收,因此如果這些對(duì)象大部分都移到了old,但是一直沒有觸發(fā)CMS GC或者Full GC,那么悲劇將會(huì)發(fā)生,因?yàn)槟愕奈锢韮?nèi)存被他們耗盡了,因此為了避免這種悲劇的發(fā)生,通過-XX:MaxDirectMemorySize來指定最大的堆外內(nèi)存大小,當(dāng)使用達(dá)到了閾值的時(shí)候?qū)⒄{(diào)用System.gc來做一次full gc,以此來回收掉沒有被使用的堆外內(nèi)存。

具體堆外內(nèi)存是如何回收的,其原理機(jī)制又是怎樣的,后面文章會(huì)詳細(xì)寫出,請(qǐng)大家持續(xù)關(guān)注腳本之家~

相關(guān)文章

  • SpringBoot使用MockMvc進(jìn)行Web集成測(cè)試的示例詳解

    SpringBoot使用MockMvc進(jìn)行Web集成測(cè)試的示例詳解

    MockMvc?是一個(gè)測(cè)試框架,可以模擬?HTTP?請(qǐng)求和響應(yīng),在本文中,我們將介紹如何使用MockMvc進(jìn)行Web集成測(cè)試,以及如何編寫測(cè)試用例來測(cè)試Spring?MVC控制器,希望對(duì)大家有所幫助
    2023-06-06
  • Java正則表達(dá)式的實(shí)例操作指南

    Java正則表達(dá)式的實(shí)例操作指南

    這篇文章主要給大家介紹了關(guān)于Java正則表達(dá)式的實(shí)例操作指南,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 小項(xiàng)目改造快速引入 mybatis的流程分析

    小項(xiàng)目改造快速引入 mybatis的流程分析

    這篇文章主要介紹了小項(xiàng)目改造快速引入 mybatis,功能方面非常簡(jiǎn)單,考慮到開發(fā)速度,直接按 springboot 項(xiàng)目進(jìn)行開發(fā),依賴方面僅僅使用 spring-boot-starter-web, spring-boot-starter-jdbc, sqljdbc4, lombook,需要的朋友可以參考下
    2022-05-05
  • SpringSecurity?用戶帳號(hào)已被鎖定的問題及解決方法

    SpringSecurity?用戶帳號(hào)已被鎖定的問題及解決方法

    這篇文章主要介紹了SpringSecurity?用戶帳號(hào)已被鎖定,本文給大家分享問題原因及解決方式,需要的朋友可以參考下
    2023-12-12
  • Windows10 Java環(huán)境變量配置過程圖解

    Windows10 Java環(huán)境變量配置過程圖解

    這篇文章主要介紹了Windows10 Java環(huán)境變量配置過程圖解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 快速入門Java中的Lambda表達(dá)式

    快速入門Java中的Lambda表達(dá)式

    Lambda作為函數(shù)式編程中的基礎(chǔ)部分,在其他編程語言中早就廣為使用,但在Java領(lǐng)域中發(fā)展較慢,直到j(luò)ava8,才開始支持Lambda。網(wǎng)上關(guān)于Lambda的教程很多,今天小編給大家分享一篇快速入手Lambda的教程。
    2016-08-08
  • Java使用Apache Tika從PDF文件中提取文本

    Java使用Apache Tika從PDF文件中提取文本

    Apache Tika 是一個(gè)內(nèi)容分析工具包,它能夠從各種類型的文檔中提取元數(shù)據(jù)和文本內(nèi)容,下面我們就來看看如何使用Apache Tika從PDF文件中提取文本吧
    2025-04-04
  • Java多線程下載文件實(shí)現(xiàn)案例詳解

    Java多線程下載文件實(shí)現(xiàn)案例詳解

    這篇文章主要介紹了Java多線程下載文件實(shí)現(xiàn)案例詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • idea快速搭建spring cloud注冊(cè)中心與注冊(cè)的方法

    idea快速搭建spring cloud注冊(cè)中心與注冊(cè)的方法

    這篇文章主要介紹了idea快速搭建spring cloud注冊(cè)中心與注冊(cè)的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-07-07
  • Mybatis獲取參數(shù)值和查詢功能的案例詳解

    Mybatis獲取參數(shù)值和查詢功能的案例詳解

    這篇文章主要介紹了Mybatis獲取參數(shù)值和查詢功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03

最新評(píng)論

万载县| 高州市| 乐东| 灵川县| 南安市| 溧阳市| 黎平县| 台安县| 定结县| 泸定县| 蛟河市| 文成县| 法库县| 石渠县| 饶河县| 齐齐哈尔市| 木兰县| 卓资县| 新蔡县| 霍山县| 凉山| 大冶市| 尚义县| 奉贤区| 仲巴县| 巴彦淖尔市| 前郭尔| 南城县| 安丘市| 东平县| 庆阳市| 平顺县| 大同市| 六安市| 福建省| 新巴尔虎左旗| 吴堡县| 新巴尔虎左旗| 丽水市| 涟源市| 明光市|