在JProfiler中,为什么我的对象不显示在All Objects视图中?

时间:2015-07-29 08:30:17

标签: jprofiler

我是JProfiler的新手。我创建了一个非常简单的测试应用程序。这是一个Main.java,主要方法是:

package com.example;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        Example e = new Example(); //Gets gc'ed?
        System.out.println(e.getMessage());
        System.in.read();
        System.exit(0);
    }
}

请注意我暂停直到按键。这样我确定主要范围不会结束,直到我按下一个键,所以我希望e存在而不是垃圾收集(如果这个假设不正确,请纠正我)。 Example类:

package com.example;

public class Example {
    public String getMessage() {
        String testString = "This is the test string. Press a key to exit.";
        return testString;
    }
}

我使用JProfiler Eclipse插件启动上述应用程序。我已经创建了一个基于Full Instrumentation配置文件的会话;我已经删除了Java EE和JDBC特定的探针,剩下的就是默认值。

现在,当探查器启动时,我转到所有对象视图,我希望找到com.example。*类,但我找不到;为什么会这样?

好的,也许我只能在使用其他视图时找到这些对象,比如分配调用树,所以我使用视图中的按钮启用分配记录(默认情况下禁用它)。它要求我点击之后计算分配,弹出一个对话框。我接受默认值,并且我提供了一个空视图,可以自动更新永恒的空虚。

然后我尝试Heap Walker。它要求我先进行转储。我得到一个对话框,为我提供选择"选择记录的对象"这是默认未选中的。我将它保留为默认值,并显示实例计数视图。但是,我在这个Classes视图中找不到我的对象。

所以我想我做的事情根本就是错误的;我该怎么做才能看到我的对象,特别是我的对象的精确实例数?

更新1: 我发现了问题的一部分。当探查器窗口出现时,它会显示“会话启动”对话框,您可以在其中选择配置文件并设置各种设置。第一个标签上有一个小部分名为" Startup"其中有一个名为"初始录像配置文件"的设置,默认情况下设置为[无录音]。当我将其保留为默认值时,我找不到Example对象。当我将其设置为" CPU录制"我可以在All Objects视图中找到我的Example对象。

更新2: 我找不到Heap Walker中的对象。当我在All Objects视图中选择com.example.Example时,我可以右键单击该对象并选择(在Heap Walker中显示对象)。当我这样做时,Heap Walker告诉我堆上没有这样的对象!是什么给了什么?

更新3: com.example.Example对象似乎有时出现,有时不出现。我无法弄清楚为什么。此外,当它显示时,它将从All对象视图中消失,即使主循环尚未退出,即使com.example.Example对象仍应存活...

更新4: 事实证明,无论在IBM的J9 JVM 上结束的范围如何,都会收集e 垃圾。请参阅我对此的回答,修改main以在按键等待后调用第二个方法,这会强制对象保持活动状态。

2 个答案:

答案 0 :(得分:6)

我终于真正解开了这个谜团。事实证明,我正在运行IBM的J9 VM。显然,J9垃圾收集更具攻击性:如果e不再在该范围内使用,它将清理主范围内的 。我已经验证了这种特定行为在Oracle的JVM中发生了

这么长的故事简短:在IBM J9上,你不能假设对象在一个块的范围内保持活跃。在Oracle的JVM上,至少在默认情况下,e块不会被垃圾收集直到块结束后,无论e的进一步使用如何。

在IBM J9上,当您想强制对象保持存在时,必须将来使用它。为了证明这一点,我修改了Example.java以包含以下内容:

package com.example;

public class Example {
    public String getFirstMessage() {
        String firstTestString = "This is the first message: Hello!";
        return firstTestString;
    }

    public String getSecondMessage() {
        String secondTestString = "This is the second message: Goodbye!";
        return secondTestString;
    }
}

然后,在main中我确保调用getSecondMessage() AFTER 等待按键(System.in.read())。这样,我们确信GC在主要范围结束之前无法清除对象,因为将来等待的调用会在用户按下某个键之后发生。所以Main.java看起来像:

package com.example;
import java.io.IOException;

public class Main {

    public static void main(String[] args) throws IOException {
        Example e = new Example();
        System.out.println(e.getFirstMessage());
        System.in.read();
        System.out.println(e.getSecondMessage());
        System.exit(0);
    }
}

无论以前认为是中的因素的CPU记录设置如何分析上述代码都将按预期工作:对象保持活动状态,因为在按下该键之前无法对其进行垃圾回收。

答案 1 :(得分:0)

  

这样我确定在我按下一个键之前主要范围没有结束,所以我>期望e存在而不是垃圾收集(如果这个>假设不正确,请纠正我)。

这是正确的。 "示例"对象将在该点由堆栈引用保存,不能进行垃圾回收。 "所有对象" view和堆walker将显示此对象。

我刚测试了你的例子,它适用于我的JProfiler 8.1.4和JProfiler 9.0.2。

使用"查看 - >查找"搜索"示例"。

的操作