<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何把Java代碼玩出花?JVM Sandbox入門(mén)教程與原理淺談

          共 9790字,需瀏覽 20分鐘

           ·

          2022-11-15 02:58

          很久沒(méi)見(jiàn),甚是想念,大家好啊!很久沒(méi)寫(xiě)技術(shù)文章了,手也會(huì)癢呢。本文干貨含量高,建議先收藏再看哦!

          在日常業(yè)務(wù)代碼開(kāi)發(fā)中,我們經(jīng)常接觸到AOP,比如熟知的Spring AOP。我們用它來(lái)做業(yè)務(wù)切面,比如登錄校驗(yàn),日志記錄,性能監(jiān)控,全局過(guò)濾器等。但Spring AOP有一個(gè)局限性,并不是所有的類(lèi)都托管在 Spring 容器中,例如很多中間件代碼、三方包代碼,Java原生代碼,都不能被Spring AOP代理到。如此一來(lái),一旦你想要做的切面邏輯并不屬于Spring的管轄范圍,或者你想實(shí)現(xiàn)脫離Spring限制的切面功能,就無(wú)法實(shí)現(xiàn)了。

          那對(duì)于Java后端應(yīng)用,有沒(méi)有一種更為通用的AOP方式呢?答案是有的,Java自身提供了JVM TI,Instrumentation等功能,允許使用者以通過(guò)一系列API完成對(duì)JVM的復(fù)雜控制。自此衍生出了很多著名的框架,比如Btrace,Arthas等等,幫助開(kāi)發(fā)者們實(shí)現(xiàn)更多更復(fù)雜的Java功能。

          JVM Sandbox也是其中的一員。當(dāng)然,不同框架的設(shè)計(jì)目的和使命是不一樣的,JVM-Sandbox的設(shè)計(jì)目的是實(shí)現(xiàn)一種在不重啟、不侵入目標(biāo)JVM應(yīng)用情況下的AOP解決方案。

          是不是看到這里還是不清楚我在講什么?別急,我舉幾個(gè)典型的JVM-Sandbox應(yīng)用場(chǎng)景:

          • 流量回放:如何錄制線上應(yīng)用每次接口請(qǐng)求的入?yún)⒑统鰠??改?dòng)應(yīng)用代碼固然可以,但成本太大,通過(guò)JVM-Sandbox,可以直接在不修改代碼的情況下,直接抓取接口的出入?yún)ⅰ?/section>
          • 安全漏洞熱修復(fù):假設(shè)某個(gè)三方包(例如出名的fastjson)又出現(xiàn)了漏洞,集團(tuán)內(nèi)那么多應(yīng)用,一個(gè)個(gè)發(fā)布新版本修復(fù),漏洞已經(jīng)造成了大量破壞。通過(guò)JVM-Sandbox,直接修改替換有漏洞的代碼,及時(shí)止損。
          • 接口故障模擬:想要模擬某個(gè)接口超時(shí)5s后返回false的情況,JVM-Sandbox很輕松就能實(shí)現(xiàn)。
          • 故障定位:像Arthas類(lèi)似的功能。
          • 接口限流:動(dòng)態(tài)對(duì)指定的接口做限流。
          • 日志打印
          • ...

          可以看到,借助JVM-Sandbox,你可以實(shí)現(xiàn)很多之前在業(yè)務(wù)代碼中做不了的事,大大拓展了可操作的范圍。

          本文圍繞JVM SandBox展開(kāi),主要介紹如下內(nèi)容:

          • JVM SandBox誕生背景
          • JVM SandBox架構(gòu)設(shè)計(jì)
          • JVM SandBox代碼實(shí)戰(zhàn)
          • JVM SandBox底層技術(shù)
          • 總結(jié)與展望

          JVM Sandbox誕生背景

          JVM Sandbox誕生的技術(shù)背景在引言中已經(jīng)贅述完畢,下面是作者開(kāi)發(fā)該框架的一些業(yè)務(wù)背景,以下描述引用自文章:

          JVM SandBox 是阿里開(kāi)源的一款 JVM 平臺(tái)非侵入式運(yùn)行期 AOP 解決方案,本質(zhì)上是一種 AOP 落地形式。那么可能有同學(xué)會(huì)問(wèn):已有成熟的 Spring AOP 解決方案,阿里巴巴為什么還要“重復(fù)造輪子”?這個(gè)問(wèn)題要回到 JVM SandBox 誕生的背景中來(lái)回答。在 2016 年中,天貓雙十一催動(dòng)了阿里巴巴內(nèi)部大量業(yè)務(wù)系統(tǒng)的改動(dòng),恰逢徐冬晨(阿里巴巴測(cè)試開(kāi)發(fā)專(zhuān)家)所在的團(tuán)隊(duì)調(diào)整,測(cè)試資源保障嚴(yán)重不足,迫使他們必須考慮更精準(zhǔn)、更便捷的老業(yè)務(wù)測(cè)試回歸驗(yàn)證方案。開(kāi)發(fā)團(tuán)隊(duì)面臨的是新接手的老系統(tǒng),老的業(yè)務(wù)代碼架構(gòu)難以滿(mǎn)足可測(cè)性的要求,很多現(xiàn)有測(cè)試框架也無(wú)法應(yīng)用到老的業(yè)務(wù)系統(tǒng)架構(gòu)中,于是需要新的測(cè)試思路和測(cè)試框架。

          為什么不采用 Spring AOP 方案呢?Spring AOP 方案的痛點(diǎn)在于不是所有業(yè)務(wù)代碼都托管在 Spring 容器中,而且更底層的中間件代碼、三方包代碼無(wú)法納入到回歸測(cè)試范圍,更糟糕的是測(cè)試框架會(huì)引入自身所依賴(lài)的類(lèi)庫(kù),經(jīng)常與業(yè)務(wù)代碼的類(lèi)庫(kù)產(chǎn)生沖突,因此,JVM SandBox 應(yīng)運(yùn)而生。

          JVM Sandbox整體架構(gòu)

          本章節(jié)不詳細(xì)講述JVM SandBox的所有架構(gòu)設(shè)計(jì),只講其中幾個(gè)最重要的特性。詳細(xì)的架構(gòu)設(shè)計(jì)可以看原框架代碼倉(cāng)庫(kù)的Wiki。

          類(lèi)隔離

          很多框架通過(guò)破壞雙親委派(我更愿意稱(chēng)之為直系親屬委派)來(lái)實(shí)現(xiàn)類(lèi)隔離,SandBox也不例外。它通過(guò)自定義的SandboxClassLoader破壞了雙親委派的約定,實(shí)現(xiàn)了幾個(gè)隔離特性:

          • 和目標(biāo)應(yīng)用的類(lèi)隔離:不用擔(dān)心加載沙箱會(huì)引起原應(yīng)用的類(lèi)污染、沖突。
          • 模塊之間類(lèi)隔離:做到模塊與模塊之間、模塊和沙箱之間、模塊和應(yīng)用之間互不干擾。

          無(wú)侵入AOP與事件驅(qū)動(dòng)

          JVM-SANDBOX屬于基于Instrumentation的動(dòng)態(tài)編織類(lèi)的AOP框架,通過(guò)精心構(gòu)造了字節(jié)碼增強(qiáng)邏輯,使得沙箱的模塊能在不違反JDK約束情況下實(shí)現(xiàn)對(duì)目標(biāo)應(yīng)用方法的無(wú)侵入運(yùn)行時(shí)AOP攔截。



          從上圖中,可以看到一個(gè)方法的整個(gè)執(zhí)行周期都被代碼“加強(qiáng)”了,能夠帶來(lái)的好處就是你在使用JVM SandBox只需要對(duì)于方法的事件進(jìn)行處理。

          // BEFORE
          try {

             /*
              * do something...
              */

              // RETURN
              return;

          } catch (Throwable cause) {
              // THROWS
          }

          在沙箱的世界觀中,任何一個(gè)Java方法的調(diào)用都可以分解為BEFORE、RETURNTHROWS三個(gè)環(huán)節(jié),由此在三個(gè)環(huán)節(jié)上引申出對(duì)應(yīng)環(huán)節(jié)的事件探測(cè)和流程控制機(jī)制。

          基于BEFORE、RETURNTHROWS三個(gè)環(huán)節(jié)事件分離,沙箱的模塊可以完成很多類(lèi)AOP的操作。

          1. 可以感知和改變方法調(diào)用的入?yún)?/section>
          2. 可以感知和改變方法調(diào)用返回值和拋出的異常
          3. 可以改變方法執(zhí)行的流程
            • 在方法體執(zhí)行之前直接返回自定義結(jié)果對(duì)象,原有方法代碼將不會(huì)被執(zhí)行
            • 在方法體返回之前重新構(gòu)造新的結(jié)果對(duì)象,甚至可以改變?yōu)閽伋霎惓?/section>
            • 在方法體拋出異常之后重新拋出新的異常,甚至可以改變?yōu)檎7祷?/section>

          一切都是事件驅(qū)動(dòng)的,這一點(diǎn)你可能很迷糊,但是在下文的實(shí)戰(zhàn)環(huán)節(jié)中,可以幫助你理解。

          JVM Sandbox代碼實(shí)戰(zhàn)

          我將實(shí)戰(zhàn)章節(jié)提前到這里,目的是方便大家快速了解使用JVM SandBox開(kāi)發(fā)是一件多么舒服的事情(相比于自己使用字節(jié)碼替換等工具)。

          使用版本:JVM-Sandbox 1.2.0

          官方源碼:https://github.com/alibaba/jvm-sandbox

          我們來(lái)實(shí)現(xiàn)一個(gè)小工具,在日常工作中,我們總會(huì)遇到一些巨大的Spring工程,里面有茫茫多的Bean和業(yè)務(wù)代碼,啟動(dòng)一個(gè)工程可能需要5分鐘甚至更久,嚴(yán)重拖累開(kāi)發(fā)效率。

          我們嘗試使用JVM Sandbox來(lái)開(kāi)發(fā)一個(gè)工具,對(duì)應(yīng)用的Spring Bean啟動(dòng)耗時(shí)進(jìn)行一次統(tǒng)計(jì)。這樣能一目了然的發(fā)現(xiàn)工程啟動(dòng)慢的主要原因,避免去盲人摸象的優(yōu)化。

          最終效果如圖:

          圖中統(tǒng)計(jì)了一個(gè)應(yīng)用從啟動(dòng)開(kāi)始到所有SpringBean的啟動(dòng)耗時(shí),按照從高到低排序,我由于是demo應(yīng)用,Bean的耗時(shí)都偏低(也沒(méi)有太多業(yè)務(wù)Bean),但在實(shí)際應(yīng)用中會(huì)有非常多幾秒甚至十幾秒才完成初始化的Bean,可以進(jìn)行針對(duì)性?xún)?yōu)化。

          在JVMSandBox中如何實(shí)現(xiàn)上面的工具?其實(shí)非常簡(jiǎn)單。

          先貼上思路的整體流程:

          首先新建Maven工程,在Maven依賴(lài)中引用JVM SandBox,官方推薦獨(dú)立工程使用parent方式。

          <parent>
              <groupId>com.alibaba.jvm.sandbox</groupId>
              <artifactId>sandbox-module-starter</artifactId>
              <version>1.2.0</version>
          </parent>

          新建一個(gè)類(lèi)作為一個(gè)JVM SandBox模塊,如下圖:

          使用@Infomation聲明mode為AGENT模式,一共有兩種模式Agent和Attach。

          • Agent:隨著JVM啟動(dòng)一起啟動(dòng)
          • Attach:在已經(jīng)運(yùn)行的JVM進(jìn)程中,動(dòng)態(tài)的插入

          我們由于是監(jiān)控JVM啟動(dòng)數(shù)據(jù),所以需要AGENT模式。

          其次,繼承com.alibaba.jvm.sandbox.api.Module和com.alibaba.jvm.sandbox.api.ModuleLifecycle。

          其中ModuleLifecycle包含了整個(gè)模塊的生命周期回調(diào)函數(shù)。

          • onLoad:模塊加載,模塊開(kāi)始加載之前調(diào)用!模塊加載是模塊生命周期的開(kāi)始,在模塊生命中期中有且只會(huì)調(diào)用一次。這里拋出異常將會(huì)是阻止模塊被加載的唯一方式,如果模塊判定加載失敗,將會(huì)釋放掉所有預(yù)申請(qǐng)的資源,模塊也不會(huì)被沙箱所感知
          • onUnload:模塊卸載,模塊開(kāi)始卸載之前調(diào)用!模塊卸載是模塊生命周期的結(jié)束,在模塊生命中期中有且只會(huì)調(diào)用一次。這里拋出異常將會(huì)是阻止模塊被卸載的唯一方式,如果模塊判定卸載失敗,將不會(huì)造成任何資源的提前關(guān)閉與釋放,模塊將能繼續(xù)正常工作
          • onActive:模塊被激活后,模塊所增強(qiáng)的類(lèi)將會(huì)被激活,所有com.alibaba.jvm.sandbox.api.listener.EventListener將開(kāi)始收到對(duì)應(yīng)的事件
          • onFrozen:模塊被凍結(jié)后,模塊所持有的所有com.alibaba.jvm.sandbox.api.listener.EventListener將被靜默,無(wú)法收到對(duì)應(yīng)的事件。需要注意的是,模塊凍結(jié)后雖然不再收到相關(guān)事件,但沙箱給對(duì)應(yīng)類(lèi)織入的增強(qiáng)代碼仍然還在。
          • loadCompleted:模塊加載完成,模塊完成加載后調(diào)用!模塊完成加載是在模塊完成所有資源加載、分配之后的回調(diào),在模塊生命中期中有且只會(huì)調(diào)用一次。這里拋出異常不會(huì)影響模塊被加載成功的結(jié)果。模塊加載完成之后,所有的基于模塊的操作都可以在這個(gè)回調(diào)中進(jìn)行

          最常用的是loadCompleted,所以我們重寫(xiě)loadCompleted類(lèi),在里面開(kāi)啟我們的監(jiān)控類(lèi)SpringBeanStartMonitor線程。

          而SpringBeanStartMonitor的核心代碼如下圖:

          使用Sandbox的doClassFilter過(guò)濾出匹配的類(lèi),這里我們是BeanFactory。

          使用doMethodFilter過(guò)濾出要監(jiān)聽(tīng)的方法,這里是initializeBean。

          里取initializeBean作為統(tǒng)計(jì)耗時(shí)的切入方法。具體為什么選擇該方法,涉及到SpringBean的啟動(dòng)生命周期,不在本文贅述范圍內(nèi)。

          接著使用moduleEventWatcher.watch(springBeanFilter, springBeanInitListener, Event.Type.BEFORE, Event.Type.RETURN);

          將我們的springBeanInitListener監(jiān)聽(tīng)器綁定到被觀測(cè)的方法上。這樣每次initializeBean被調(diào)用,都會(huì)走到我們的監(jiān)聽(tīng)器邏輯。

          監(jiān)聽(tīng)器的主要邏輯如下:

          代碼有點(diǎn)長(zhǎng),不必細(xì)看,主要就是在原方法的BeforeEvent(進(jìn)入前)和ReturnEvent(執(zhí)行正常返回后)執(zhí)行上述的切面邏輯,我這里便是使用了一個(gè)MAP存儲(chǔ)每個(gè)Bean的初始化開(kāi)始和結(jié)束時(shí)間,最終統(tǒng)計(jì)出初始化耗時(shí)。

          最終,我們還需要一個(gè)方法來(lái)知道我們的原始Spring應(yīng)用已經(jīng)啟動(dòng)完畢,這樣我們可以手動(dòng)卸載我們的Sandbox模塊,畢竟他已經(jīng)完成了他的歷史使命,不需要再依附在主進(jìn)程上。

          我們通過(guò)一個(gè)簡(jiǎn)陋的辦法,檢查http://127.0.0.1:8080/是否會(huì)返回小于500的狀態(tài)碼,來(lái)判斷Spring容器是否已經(jīng)啟動(dòng)。當(dāng)然如果你的Spring沒(méi)有使用Web框架,就不能用這個(gè)方法來(lái)判斷啟動(dòng)完成,你也許可以通過(guò)Spring自己的生命周期鉤子函數(shù)來(lái)實(shí)現(xiàn),這里我是偷了個(gè)懶。

          整個(gè)SpringBean監(jiān)聽(tīng)模塊的開(kāi)發(fā)就完成了,你可以感受到,你的開(kāi)發(fā)和日常業(yè)務(wù)開(kāi)發(fā)幾乎沒(méi)有區(qū)別,這就是JVM Sandbox帶給你的最大好處。

          上述源碼放在了我的Github倉(cāng)庫(kù):

          https://github.com/monitor4all/javaMonitor

          JVM Sandbox底層技術(shù)

          整個(gè)JVM Sandbox的入門(mén)使用基本上講完了,上文提到了一些JVM技術(shù)名詞,可能小伙伴們聽(tīng)過(guò)但不是特別了解。這里簡(jiǎn)單闡述幾個(gè)重要的概念,理清楚這幾個(gè)概念之間的關(guān)系,以便大家更好的理解JVM Sandbox底層的實(shí)現(xiàn)。

          JVMTI

          JVMTI(JVM Tool Interface)是 Java 虛擬機(jī)所提供的 native 編程接口,JVMTI可以用來(lái)開(kāi)發(fā)并監(jiān)控虛擬機(jī),可以查看JVM內(nèi)部的狀態(tài),并控制JVM應(yīng)用程序的執(zhí)行??蓪?shí)現(xiàn)的功能包括但不限于:調(diào)試、監(jiān)控、線程分析、覆蓋率分析工具等。

          很多java監(jiān)控、診斷工具都是基于這種形式來(lái)工作的。如果arthas、jinfo、brace等,雖然這些工具底層是JVM TI,但是它們還使用到了上層工具JavaAgent。

          JavaAgent和Instrumentation

          Javaagent是java命令的一個(gè)參數(shù)。參數(shù) javaagent 可以用于指定一個(gè) jar 包。

          -agentlib:<libname>[=<選項(xiàng)>] 加載本機(jī)代理庫(kù) <libname>, 例如 -agentlib:hprof
           另請(qǐng)參閱 -agentlib:jdwp=help 和 -agentlib:hprof=help
          -agentpath:<pathname>[=<選項(xiàng)>]
           按完整路徑名加載本機(jī)代理庫(kù)
          -javaagent:<jarpath>[=<選項(xiàng)>]
           加載 Java 編程語(yǔ)言代理, 請(qǐng)參閱 java.lang.instrument

          在上面-javaagent參數(shù)中提到了參閱java.lang.instrument,這是在rt.jar 中定義的一個(gè)包,該包提供了一些工具幫助開(kāi)發(fā)人員在 Java 程序運(yùn)行時(shí),動(dòng)態(tài)修改系統(tǒng)中的 Class 類(lèi)型。其中,使用該軟件包的一個(gè)關(guān)鍵組件就是 Javaagent。從名字上看,似乎是個(gè) Java 代理之類(lèi)的,而實(shí)際上,他的功能更像是一個(gè)Class 類(lèi)型的轉(zhuǎn)換器,他可以在運(yùn)行時(shí)接受重新外部請(qǐng)求,對(duì)Class類(lèi)型進(jìn)行修改。

          Instrumentation的底層實(shí)現(xiàn)依賴(lài)于JVMTI。

          JVM 會(huì)優(yōu)先加載 帶 Instrumentation 簽名的方法,加載成功忽略第二種,如果第一種沒(méi)有,則加載第二種方法。

          Instrumentation支持的接口:

          public interface Instrumentation {
              //添加一個(gè)ClassFileTransformer
              //之后類(lèi)加載時(shí)都會(huì)經(jīng)過(guò)這個(gè)ClassFileTransformer轉(zhuǎn)換
              void addTransformer(ClassFileTransformer transformer, boolean canRetransform);

              void addTransformer(ClassFileTransformer transformer);
              //移除ClassFileTransformer
              boolean removeTransformer(ClassFileTransformer transformer);

              boolean isRetransformClassesSupported();
              //將一些已經(jīng)加載過(guò)的類(lèi)重新拿出來(lái)經(jīng)過(guò)注冊(cè)好的ClassFileTransformer轉(zhuǎn)換
              //retransformation可以修改方法體,但是不能變更方法簽名、增加和刪除方法/類(lèi)的成員屬性
              void retransformClasses(Class<?>... classes) throws UnmodifiableClassException;

              boolean isRedefineClassesSupported();

              //重新定義某個(gè)類(lèi)
              void redefineClasses(ClassDefinition... definitions)
                  throws  ClassNotFoundException, UnmodifiableClassException
          ;

              boolean isModifiableClass(Class<?> theClass);

              @SuppressWarnings("rawtypes")
              Class[] getAllLoadedClasses();

              @SuppressWarnings("rawtypes")
              Class[] getInitiatedClasses(ClassLoader loader);

              long getObjectSize(Object objectToSize);

              void appendToBootstrapClassLoaderSearch(JarFile jarfile);

              void appendToSystemClassLoaderSearch(JarFile jarfile);

              boolean isNativeMethodPrefixSupported();

              void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);
          }

          Instrumentation的局限性:

          • 不能通過(guò)字節(jié)碼文件和自定義的類(lèi)名重新定義一個(gè)本來(lái)不存在的類(lèi)
          • 增強(qiáng)類(lèi)和老類(lèi)必須遵循很多限制:比如新類(lèi)和老類(lèi)的父類(lèi)必須相同;新類(lèi)和老類(lèi)實(shí)現(xiàn)的接口數(shù)也要相同,并且是相同的接口;新類(lèi)和老類(lèi)訪問(wèn)符必須一致。新類(lèi)和老類(lèi)字段數(shù)和字段名要一致;新類(lèi)和老類(lèi)新增或刪除的方法必須是private static/final修飾的;

          更詳細(xì)的原理闡述可以看下文:

          https://www.cnblogs.com/rickiyang/p/11368932.html

          再談Attach和Agent

          上面的實(shí)戰(zhàn)章節(jié)中已經(jīng)提到了attach和agent兩者的區(qū)別,這里再展開(kāi)聊聊。

          在Instrumentation中,Agent模式是通過(guò)-javaagent:<jarpath>[=<選項(xiàng)>]從應(yīng)用啟動(dòng)時(shí)候就插樁,隨著應(yīng)用一起啟動(dòng)。它要求指定的類(lèi)中必須要有premain()方法,并且對(duì)premain方法的簽名也有要求,簽名必須滿(mǎn)足以下兩種格式:

          public static void premain(String agentArgs, Instrumentation inst)
              
          public static void premain(String agentArgs)

          一個(gè)java程序中-javaagent參數(shù)的個(gè)數(shù)是沒(méi)有限制的,所以可以添加任意多個(gè)javaagent。所有的java agent會(huì)按照你定義的順序執(zhí)行,例如:

          java -javaagent:agent1.jar -javaagent:agent2.jar -jar MyProgram.jar

          上面介紹Agent模式的Instrumentation是在 JDK 1.5中提供的,在1.6中,提供了attach方式的Instrumentation,你需要的是agentmain方法,并且簽名如下:

          public static void agentmain (String agentArgs, Instrumentation inst)

          public static void agentmain (String agentArgs)

          這兩種方式各有不同用途,一般來(lái)說(shuō),Attach方式適合于動(dòng)態(tài)的對(duì)代碼進(jìn)行功能修改,在排查問(wèn)題的時(shí)候用的比較多。而Agent模式隨著應(yīng)用啟動(dòng),所以經(jīng)常用于提前實(shí)現(xiàn)一些增強(qiáng)功能,比如我上面實(shí)戰(zhàn)中的啟動(dòng)觀測(cè),應(yīng)用防火墻,限流策略等等。

          總結(jié)

          本文花了較短的篇幅重點(diǎn)介紹了JVM Sandbox的功能,實(shí)際用法,以及基礎(chǔ)原理。它通過(guò)封裝一些底層JVM控制的框架,使得對(duì)JVM層面的AOP開(kāi)發(fā)變的異常簡(jiǎn)單,就像作者自己所說(shuō)“JVM-SANDBOX還能幫助你做很多很多,取決于你的腦洞有多大了。

          筆者在公司內(nèi)部也通過(guò)它實(shí)現(xiàn)了很多小工具,比如上面的應(yīng)用啟動(dòng)數(shù)據(jù)觀測(cè)(公司內(nèi)部是一個(gè)更為穩(wěn)定復(fù)雜的版本,還監(jiān)控了大量中間件的數(shù)據(jù)),幫助了很多部門(mén)同事,優(yōu)化他們應(yīng)用的啟動(dòng)速度。所以如果對(duì)JVM感興趣,不妨大開(kāi)腦洞,想一想JVM Sandbox還能在哪里幫助到你的工作,給自己的工作添彩。

          參考

          https://www.infoq.cn/article/tsy4lgjvsfweuxebw*gp

          https://www.cnblogs.com/rickiyang/p/11368932.html

          https://www.jianshu.com/p/eff047d4480a


          往期精彩文章:


          Java19 新特性虛擬線程!Java官方協(xié)程支持它要來(lái)了嗎?


          你買(mǎi)的云服務(wù)器,可能正泡在水里。


          一次完整的JVM堆外內(nèi)存泄漏故障排查記錄


          記一次線上RPC超時(shí)故障排查及后續(xù)GC調(diào)優(yōu)思路


          管理訂單狀態(tài),該用上狀態(tài)機(jī)嗎?


          - END -


          瀏覽 92
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  狠狠干中文字幕 | 伊人狼人综合 | 亚洲无人区码一码二码 | 91豆花网站在线视频 | gogo人体视频 |