当前位置: 首页 > 知识库问答 >
问题:

在JProfiler中,为什么我的对象没有显示在“所有对象”视图中?

杨志强
2023-03-14

我是JProfiler的新手。我创建了一个非常简单的测试应用程序。这是一个带有main方法的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存在并且不会被垃圾收集(如果这个假设不正确,请纠正我)。示例类:

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插件启动上述应用程序。我创建了一个基于完整仪器配置文件的会话;我已经删除了Java EE和JDBC特定的探测,其余的都是默认的。

现在,当分析器启动时,我进入所有对象视图,我希望找到com.example.*类,但我没有找到;为什么会这样?

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

然后我试着用堆步行器。它要求我先把垃圾倒出来。我得到了一个对话框,它为我提供了“选择记录的对象”的选项,这是默认未选中的。我将其保留为默认值,并显示一个实例计数视图。然而,在我看到的这个类视图中,我的对象是不可找到的。

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

更新1:我发现了问题的一部分。当profiler窗口出现时,它会显示会话启动对话框,您可以在其中选择配置文件并设置各种设置。第一个选项卡上有一个叫做“启动”的小部分,它有一个叫做“初始录制配置文件”的设置,默认设置为[无录制]。当我将其保留为默认值时,我找不到示例对象。当我将其设置为“CPU录制”时,我可以在“所有对象”视图中找到我的示例对象。

更新2:我在Heap Walker中找不到该对象。当我选择com时。实例例如,在“所有对象”视图中,我可以右键单击对象并选择(在Heap Walker中显示对象)。当我这么做时,堆行者告诉我堆上没有这样的对象!有什么好处?

更新3:com.example.示例对象似乎有时会出现,有时不会。我不知道为什么。此外,当它出现时,它将从所有对象视图中消失,即使主循环尚未退出,即使com.example.示例对象应该仍然活着...

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

共有2个答案

柴衡
2023-03-14

这样,我可以确定主范围不会结束,直到我按下一个键,所以我

这是正确的。此时,“示例”对象将由堆栈引用持有,不能被垃圾回收。“所有对象”视图和堆遍历器都将显示此对象。

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

使用“查看-

朱翔
2023-03-14

我终于真正解开了这个谜团。原来我在运行IBM的J9虚拟机。显然,J9垃圾收集更具攻击性:如果不再在主范围内使用e,它将在主范围内清理e。我已经验证了Oracle的JVM不会出现这种特定行为。

长话短说:在IBM J9上,您不能假设对象在块范围内保持活动。在Oracle的JVM上,至少在默认情况下,在块结束之前不会对e进行垃圾收集,而不管e的进一步使用。

在IBM J9上,当您想要强制对象保持存在时,必须在将来使用它。为了证明这一点,我修改了示例。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;
    }
}

然后,大体上,我确保在等待按键(System.in.read())之后调用getSecondMessage()。通过这种方式,我们可以确定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记录设置如何,分析上述代码都将按预期工作:对象保持活动状态,因为在按下键之前无法对其进行垃圾收集。

 类似资料:
  • 这应该是一个相对简单的问题,但它让我发疯。我正在尝试在JavaFX中创建扫雷器(主要用于练习),但我甚至无法显示一个简单的矩形。我以前运行过一次游戏,但我试图使游戏更加抽象,因此更容易编码,但我遇到了不显示任何问题。 我消除了所有无关的代码,使其尽可能简单。我基本上是在尝试创建一个名为Box的具有特定颜色和大小的矩形,将框添加到窗格中,并显示窗格。为了使Box成为可以在窗格上显示的节点,我使Box

  • 我试图显示一个对象中的所有值,但它给了我“必须声明”错误。 我尝试了下面的代码,但仍然出现相同的错误。 而我的对象是: 错误: 错误报告-ORA-06550:第5行,第38列:PLS-00302:组件'ID'必须声明ORA-06550:第5行,第7列:PL/SQL:语句忽略ORA-06550:第6行,第38列:PLS-00302:组件'G'必须声明ORA-06550:第6行,第7列:PL/SQL:

  • 在JS中,如果我将一个字符串记录到控制台,它是否没有正确显示? 后果 那么为什么显示的是[object],而不是值呢?它就像是在附加字符串的情况下更改类型?

  • 在我的maven构建中,我有很长时间的运行测试。这些测试是使用故障保护插件运行的集成测试(

  • 我使用的是sequelize ORM,而对于DB我使用的是MySQL,在其中我关联了两个表并获得了数据,但我希望第二个数据(另一个表的数据)不应该像嵌套对象一样进来,而是我们可以在一个对象中显示所有数据(两个表的数据)。 让我展示一下屏幕快照。 我想要的东西。 忽略数据的键和值,但我的问题是,我们是否可以在同一对象中显示另一个表的数据(像inner join一样),而不是像嵌套对象中的数据。 任何

  • 问题内容: 在一个我目前正在从事的项目中,我遇到了一个角度异常: 在寻找解决方案的搜索中,我直接在浏览器中输入了Web服务的URL,但令人惊讶的是,我没有收到预期的数组。 Web服务类: 当我输入网址时,我希望看到带有JSON对象的JSON数组: 但是,相反,我收到的JSON对象的属性与我期望的JSON对象相同,没有任何数组: 所以我想知道为什么没有数组,当我添加另一个Clazz对象时会发生什么。