性能文章>JConsole 里的 GC 按钮。>

JConsole 里的 GC 按钮。原创

https://a.perfma.net/img/2382850
1年前
246503

是这样的,前几天有个小伙伴给我发了段代码:

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++) {
            //稍作延迟,令监视曲线的变化更加明显
            Thread.sleep(50);
            list.add(new OOMObject());
        }
        System.gc();
    }
    public static void main(String[] args) throws InterruptedException {
        fillHeap(1000);
    }
}

我看了一眼:问发生肾么事儿了?

他给我说:

歪歪,这个代码是我看书上演示 JConsole 检测内存的测试案例。但是我观察的时候看到了这里有个[执行GC]的按钮,手贱点了一下。我就想问一下这里的[执行GC]和代码里面的 System.gc() 是一回事吗?

我一看:嚯,好家伙,这问题有点意思啊。这我还真不知道呢。

于是我给他说:

这不,很快啊,我就研究完了。

先说结论:

JConsole 里面点击按钮执行 GC 和在程序里面调用 System.gc() 是一回事。

研究过程

从哪里开始研究呢?

来,一起说一遍:源码之下无秘密。

你知道的,JConsole 这画风一看就是 Java 用 swing 编程写出来的玩意。

好巧不巧,我大学的时候学 swing 学的风生水起,因为我太喜欢那种运行起来就能直接看到画面的感觉了。

对于初学者是一种鼓励的感觉。

那么就很简单了,我只要找到 JConsole 对应的源码,看看点击 GC 按钮的时候它执行的源码是什么不就完事了吗?

那么问题来了,JConsole 的源码去哪里找呢?

OpenJDK 里面就有:

http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/758db1c4c65c/

把下载下来的源码导入到 Idea 里面,然后全局查找 JConsole 类:

可以看到在源码中的路径为:

sun.tools.jconsole.JConsole

这里还有我们熟悉的 javac、jcmd、jinfo、jmap、jps、jstack、jstat 这些小工具。

找到 JConsole 的源码之后怎么办呢?

读呗。

但是我大概读了 5 分钟的样子,感觉不对劲。

swing 编程我基本上已经全部还给老师了,看着有点懵逼的样子,只能连蒙带猜的看个大概,效率太低了。

但是我看的时候看到这行代码的时候,我突然冒出了另外一个思路:

你说这行是在干啥?

用脚指头猜也知道是设置 title。

title 是什么?

诶,不就是 JConsole 页面的这个玩意吗?

这一点我还是没还给老师的。

在源码里面 title 值是从这里取出来的:

title = Messages.JAVA_MONITORING___MANAGEMENT_CONSOLE;

这是个啥东西?

我也不知道,反正我二话不说上去就是一个全局搜索,路子就是这么野:

这一看,嚯,这不是多个配置文件嘛,整的还是国际化。

那一串看着像是乱码的玩意,很明显,是 Unicode 嘛,来转义一波:

你说这事整的,还真被我猜对了。

验证了这个点,接下来的思路就很简单了。

这不是还有[执行]两个字的中文嘛?

执行对应的 Unicode 是 \u6267\u884c 。

你懂我意思吧?

上来就是一个反向操作,回手掏:

PERFORM_GC=\u6267\u884c &GC

仅有的那点 swing 编程知识告诉我,接下来只要找 PERFORM_GC 对应的文案是在哪里用的,不就能拿到这个 button 了吗?

屁话少说,直接上来又是一个全局搜索:

看到这行代码的时候我觉得我真特么的是一个及里日。

及里儿斯就是 genius,天才的意思。

来,看一眼这行代码:

这个按钮的变量的名称就是 gcButton。

而当我看到这个 gcButton 位于的 Java 类的时候,我才发现我大意了:

sun.tools.jconsole.MemoryTab

MemoryTab,内存选项卡,多贴切啊,简直就是见名知意了。

而这两个类隔的并不远,我要是把类名看一眼,也不至于这样反向去查:

这波看起来是走远了一点,但是不亏,反正就是找到了 gcButton。

最终看一眼 gcButton 被调用的地方:

真相就是一步之遥了。

这代码对应的 gc() 方法是啥呢?

proxyClient.getMemoryMXBean().gc();

首先它要获取一个 MemoryMXBean 出来,然后调用它的 gc 方法:

而 MemoryMXBean 是一个接口,它对应的实现类是:

sun.management.MemoryImpl

到这里了,就真相大白了。

这里的 gc() 方法和 System.gc() 一模一样:

所以,再次说一下结论:

JConsole 里面点击按钮执行 GC 和在程序里面调用 System.gc() 是一回事。

我承认,整个查找的过程中除了我的“及里儿斯”之外,还有一点运气的成分在里面。

诶,但是最终我就是找到了,你说这事搞的简直没地儿说理去。

点赞收藏
分类:标签:
why技术
请先登录,感受更多精彩内容
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

日常Bug排查-集群逐步失去响应

日常Bug排查-集群逐步失去响应

浅析AbstractQueuedSynchronizer

浅析AbstractQueuedSynchronizer

3
0