侧边栏壁纸
博主头像
why

一个主要敲代码,经常怼文章,偶尔拍视频的成都人。

  • 累计撰写 197 篇文章
  • 累计创建 11 个标签
  • 累计收到 101 条评论

就这?一个没啥卵用的知识点。

why
why
2021-06-11 / 0 评论 / 2 点赞 / 255 阅读 / 2,363 字
温馨提示:
关注公众号why技术,第一时间接收最新文章。

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

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技术]吧,文章写好后第一时间会先发布在公众号里面。

写文章很累的,需要一点正反馈。你的关注,就是强有力的正反馈!

才疏学浅,难免会有纰漏,如果你发现了错误的地方,还请你留言给我指出来,我对其加以修改。

抱拳了,铁子!

0

评论区