1

我正在尝试获取正在运行的 JVM 中某个类的所有实例的平均大小。我可以使用 jcmd 或类似工具创建堆转储,但这需要几秒钟,这是一个生产服务器,所以我宁愿有更快的东西。jcmd 有一个选项可以创建这种格式的直方图:

 num     #instances         #bytes  class name
----------------------------------------------
   1:         84907      559415720  [I
   2:       9572537      229740888  java.lang.String
   3:        803323      142900392  [C
   4:       3190710      102102720  java.util.Hashtable$Entry

这似乎很有希望,但我认为字节大小是浅的而不是保留的内存。有没有办法创建具有保留大小的相同直方图?或者也许是另一种快速获取类实例平均大小的方法?

我知道 GDB 方法,但它不适合,因为命令序列将花费我几秒钟的时间来输入,而这大约是使用 jcmd 进行堆转储所需的时间。

4

1 回答 1

1

我认为报告对象“深度大小”直方图的通用工具在技术上是不可行的。

为什么不?

如果对象的“深度大小”取决于其类的语义,我们就会遇到通用工具不知道对象边界在哪里的问题。可以使用标准类型(如StringStringBufferHashMap. 然而:

  • 这种方法不能扩展,也不能处理应用程序和 3rd 方库类。
  • 对于某些类型(例如集合类型),语义边界(即用户想要查找的内容)可能与上下文相关。

或者,如果一个对象的“深度大小”只是可以从它到达的所有对象的大小之和,那么存在两个问题:

  • 会出现严重的多算。例如,字符串的大部分内存使用都在字符数组中。这些数组将被计算两次:一次在String对象的可达性图中,第二次作为字符数组。对于复杂的对象,过度计数可能会使度量变得无用。

  • 计算直方图的平均值会非常昂贵。一种简单的方法是对堆中的每个对象执行可达性图遍历。我不知道是否有更快的替代方案。

  • 另一种方法是通过在实例计数中不包括“内部”对象来避免重复计算。不幸的是,您会遇到同样具有误导性的现象,即(例如)更复杂对象中的内部字符串、集合等会消失。这意味着您无法再准确估计它们的平均尺寸。

我不认为有一个实际可行的计数方案。


话虽如此,您当前使用的(OpenJDK)工具的源代码可供下载。您可以修改工具以不同方式分析对象大小。但我不认为它会在开发工作或修改工具的速度方面“快速”。

于 2020-02-16T14:29:40.987 回答