就這?一個(gè)沒(méi)啥卵用的知識(shí)點(diǎn).
你好呀,我是whywhy。
嗯,是讀者叫我歪歪的。

是這樣的,前幾天有個(gè)小伙伴給我發(fā)了段代碼:
public?class?Main?{
????static?class?OOMObject{
????????public?byte[]?placeholder=new?byte[64*1024];
????}
????public?static?void?fillHeap(int?num)?throws?InterruptedException?{
????????List<OOMObject>?list?=?new?ArrayList<>();
????????for?(int?i?=?0;?i?<?num;?i++)?{
????????????//稍作延遲,令監(jiān)視曲線的變化更加明顯
????????????Thread.sleep(50);
????????????list.add(new?OOMObject());
????????}
????????System.gc();
????}
????public?static?void?main(String[]?args)?throws?InterruptedException?{
????????fillHeap(1000);
????}
}
我看了一眼:?jiǎn)柊l(fā)生腎么事兒了?
他給我說(shuō):
歪歪,這個(gè)代碼是我看書(shū)上演示 JConsole 檢測(cè)內(nèi)存的測(cè)試案例。但是我觀察的時(shí)候看到了這里有個(gè)[執(zhí)行GC]的按鈕,手賤點(diǎn)了一下。我就想問(wèn)一下這里的[執(zhí)行GC]和代碼里面的 System.gc() 是一回事嗎?

我一看:嚯,好家伙,這問(wèn)題有點(diǎn)意思啊。這我還真不知道呢。
于是我給他說(shuō):

這不,很快啊,我就研究完了。
先說(shuō)結(jié)論:
JConsole 里面點(diǎn)擊按鈕執(zhí)行 GC 和在程序里面調(diào)用 System.gc() 是一回事。
研究過(guò)程
從哪里開(kāi)始研究呢?
來(lái),一起說(shuō)一遍:源碼之下無(wú)秘密。
你知道的,JConsole 這畫(huà)風(fēng)一看就是 Java 用 swing 編程寫(xiě)出來(lái)的玩意。
好巧不巧,我大學(xué)的時(shí)候?qū)W swing 學(xué)的風(fēng)生水起,因?yàn)槲姨矚g那種運(yùn)行起來(lái)就能直接看到畫(huà)面的感覺(jué)了。
對(duì)于初學(xué)者是一種鼓勵(lì)的感覺(jué)。

那么就很簡(jiǎn)單了,我只要找到 JConsole 對(duì)應(yīng)的源碼,看看點(diǎn)擊 GC 按鈕的時(shí)候它執(zhí)行的源碼是什么不就完事了嗎?

那么問(wèn)題來(lái)了,JConsole 的源碼去哪里找呢?
OpenJDK 里面就有:
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/758db1c4c65c/
把下載下來(lái)的源碼導(dǎo)入到 Idea 里面,然后全局查找 JConsole 類(lèi):

可以看到在源碼中的路徑為:
sun.tools.jconsole.JConsole

這里還有我們熟悉的 javac、jcmd、jinfo、jmap、jps、jstack、jstat 這些小工具。
找到 JConsole 的源碼之后怎么辦呢?
讀唄。
但是我大概讀了 5 分鐘的樣子,感覺(jué)不對(duì)勁。

swing 編程我基本上已經(jīng)全部還給老師了,看著有點(diǎn)懵逼的樣子,只能連蒙帶猜的看個(gè)大概,效率太低了。
但是我看的時(shí)候看到這行代碼的時(shí)候,我突然冒出了另外一個(gè)思路:

你說(shuō)這行是在干啥?
用腳指頭猜也知道是設(shè)置 title。
title 是什么?
誒,不就是 JConsole 頁(yè)面的這個(gè)玩意嗎?

這一點(diǎn)我還是沒(méi)還給老師的。
在源碼里面 title 值是從這里取出來(lái)的:
title = Messages.JAVA_MONITORING___MANAGEMENT_CONSOLE;
這是個(gè)啥東西?
我也不知道,反正我二話不說(shuō)上去就是一個(gè)全局搜索,路子就是這么野:

這一看,嚯,這不是多個(gè)配置文件嘛,整的還是國(guó)際化。

那一串看著像是亂碼的玩意,很明顯,是 Unicode 嘛,來(lái)轉(zhuǎn)義一波:

你說(shuō)這事整的,還真被我猜對(duì)了。
驗(yàn)證了這個(gè)點(diǎn),接下來(lái)的思路就很簡(jiǎn)單了。

這不是還有[執(zhí)行]兩個(gè)字的中文嘛?

執(zhí)行對(duì)應(yīng)的 Unicode 是 \u6267\u884c 。
你懂我意思吧?

上來(lái)就是一個(gè)反向操作,回手掏:

PERFORM_GC=\u6267\u884c &GC
僅有的那點(diǎn) swing 編程知識(shí)告訴我,接下來(lái)只要找 PERFORM_GC 對(duì)應(yīng)的文案是在哪里用的,不就能拿到這個(gè) button 了嗎?
屁話少說(shuō),直接上來(lái)又是一個(gè)全局搜索:

看到這行代碼的時(shí)候我覺(jué)得我真特么的是一個(gè)雞里兒斯。
雞里兒斯就是 genius,天才的意思。

來(lái),看一眼這行代碼:

這個(gè)按鈕的變量的名稱(chēng)就是 gcButton。
而當(dāng)我看到這個(gè) gcButton 位于的 Java 類(lèi)的時(shí)候,我才發(fā)現(xiàn)我大意了:
sun.tools.jconsole.MemoryTab
MemoryTab,內(nèi)存選項(xiàng)卡,多貼切啊,簡(jiǎn)直就是見(jiàn)名知意了。
而這兩個(gè)類(lèi)隔的并不遠(yuǎn),我要是把類(lèi)名看一眼,也不至于這樣反向去查:

這波看起來(lái)是走遠(yuǎn)了一點(diǎn),但是不虧,反正就是找到了 gcButton。
最終看一眼 gcButton 被調(diào)用的地方:

真相就是一步之遙了。
這代碼對(duì)應(yīng)的 gc() 方法是啥呢?
proxyClient.getMemoryMXBean().gc();
首先它要獲取一個(gè) MemoryMXBean 出來(lái),然后調(diào)用它的 gc 方法:

而 MemoryMXBean 是一個(gè)接口,它對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)是:
sun.management.MemoryImpl

到這里了,就真相大白了。
這里的 gc() 方法和 System.gc() 一模一樣:

所以,再次說(shuō)一下結(jié)論:
JConsole 里面點(diǎn)擊按鈕執(zhí)行 GC 和在程序里面調(diào)用 System.gc() 是一回事。
我承認(rèn),整個(gè)查找的過(guò)程中除了我的“雞里兒斯”之外,還有一點(diǎn)運(yùn)氣的成分在里面。
誒,但是最終我就是找到了,你說(shuō)這事搞的簡(jiǎn)直沒(méi)地兒說(shuō)理去。
那你看完了,我問(wèn)你一個(gè)問(wèn)題:
你覺(jué)得你知道了這個(gè)點(diǎn),有什么卵用嗎?
是的,沒(méi)有。
那么恭喜你,又在我這里學(xué)到了一個(gè)沒(méi)有任何卵用的知識(shí)點(diǎn)。

好了,就這樣,明天端午了。
大家端午安康。
你看,我都祝你端午安康了,你給我安排一個(gè)“一鍵三連”問(wèn)題不大吧?

推薦???:我不服!這開(kāi)源項(xiàng)目居然才888個(gè)星!
推薦???:曝光一個(gè)網(wǎng)站,我周末就耗在上面了。推薦???:面試官:啥是請(qǐng)求重發(fā)啊?推薦???:曾趟過(guò)微服務(wù)這條河,暗潮洶涌。
推薦???:414天前,我以為這是編程玄學(xué)...我是 why,一個(gè)主要寫(xiě)代碼,經(jīng)常寫(xiě)文章,偶爾拍視頻的程序猿。歡迎關(guān)注我呀。
