代码之家  ›  专栏  ›  技术社区  ›  Sebastien Lorber

我们可以在JVM内存中查看对象吗?

  •  8
  • Sebastien Lorber  · 技术社区  · 16 年前

    在工作中,我们发现在某些情况下(特别是慢的情况下),我们有不同的行为,在重启时获得。

    我们猜测缓存未正确初始化,或者可能是并发问题… 不管怎样,它在任何其他环境下都不能复制,而不是生产。

    我们实际上没有可以激活的记录器…这是一个旧组件…

    因此,我想知道是否有工具可以帮助我们查看JVM内存中存在的不同对象,以便检查缓存的内容…

    谢谢您!

    编辑:

    我没有直接访问生产服务器的权限,我们的应用服务器是WebLogic10,我没有指向该对象的指针,但我知道缓存对象类型…

    编辑2:

    我们的服务器运行在JRE 1.5上,是否可以使用JMAP?在JDK5中找不到它:( 另外,远程调试可能很好,但出于安全原因,我们不能……

    EdTe3:

    实际上jhat+visualvm对我来说没问题,我在dump中找到了我的对象,但是我不能正确地读取hashmap(对象包含大约60000个项目)。 有没有一个工具可以友好地读取当前的地图?我需要找到一个键的值(或者它在地图中的存在),而不需要手动浏览60K记录。 事实上,我在EclipseMat论坛上看到,它也不可能与它一起使用……

    编辑4: 经过一些经验,我真的很喜欢像visualvm这样的工具。也用了yourkit。 有一些有用的功能,比如OQL,可以找到您需要查看的正确实例…

    3 回复  |  直到 16 年前
        1
  •  7
  •   mezmo    16 年前

    这基本上是为了扩大威尔所说的内容。 我已经取得了巨大的成功,让我们的管理员对我们的生产系统进行成堆的转储,不过要注意的是,在转储完成之前,您正在转储的特定服务器将不会响应。然后获取该文件并使用EclipseMat插件查看它。如果您不喜欢Eclipse,也可以使用NetBeans和普通的VisualVM插件。这可以创建一些大文件,但是您可能需要在64位系统上运行。

        2
  •  4
  •   Will Hartung    16 年前

    运行JMAP来转储大量对象实例是相当容易的,但我不知道这是否是您真正感兴趣的。

    您还可以使用jmap对整个堆进行堆转储,通过它(和jhat),您可以看到对象关系(即什么对象指向什么),但不一定是对象内容。

    当然,数据在堆转储中,它不是“单击离开”可见。

    我认为一些专业的分析人员会让您内省堆转储中的对象。

    另外,您最好在应用程序中添加一些特定的工具,以提供您正在寻找的特定内省,由自定义代码、JMX或其他任何东西触发。

        3
  •  3
  •   aperkins    16 年前

    您是否可以访问对象的句柄/指针?如果是这样,您可以在调试模式下启动它,并在类似Eclipse的调试器中查看它。这将允许您检查变量等。

    或者,您可以编写一个小记录器,它反射性地遍历类并记录正在发生的事情。所有这些都假定您有一个可以开始单步执行代码的位置,或者可以获取对缓存值的引用。


    编辑:正如我在评论中提到的,我不知道如何在没有某种引用或引用链接的情况下访问对象。例如,对象是否封装在另一个对象中?如果是这样,您可以执行如下操作:

    Class<?> objectClass = myPointer.getClass();
    Field[] objectFields = objectClass.getDeclaredFields();
    for (Field field : objectFields) {
        field.setAccessible(true);
        //Or whatever you would need to do to get the information you need
        System.out.println(field.get(myPointer).toString());
    }
    

    您还可以执行以下操作:

    Field targetField = objectClass.getDeclaredField("myFieldName");
    targetField.setAccessible(true);
    MyOldObjectType target = (MyOldObjectType)targetField.get(myPointer);
    //do whatever you need to do here
    

    请注意,所有反射方法都会抛出异常,因此您需要酌情处理这些异常。也, setAccessible(true) 意味着您可以访问对象上的私有字段和方法。这是 非常危险 -只有在你必须使用的时候才使用它。