3

我想研究 Java 程序的内存访问模式。是否有一个框架或方法可以实现这一目标。

假设有一个程序 P,它按顺序访问内存地址 m1、m2、m3 等。我希望能够按该顺序查看这些访问,如果可能的话,访问的是什么类型的对象?

更新(添加到 Durandal 的建议):

我总是可以通过运行带有 PIN 检测的 Java 程序来找到内存访问模式。除了这样做之外,这一切都很好,我将丢失内存地址到对象的映射。我想做的研究的一个重要方面是能够将内存使用情况映射到相应的类型(类)。

尽管正确地提到内存使用模式将取决于 JVM 实现,但我想将其视为研究的后续步骤。现在,我只在寻找字节码检测。(如果我走错了方向,请纠正我!)

我认为字节码检测将如何帮助我分析缓存使用情况? 在任何解释之前!这只是我想做的一方面。当内存访问模式(从 PIN 或修改后的 VM 或其他)不足以为我提供有关不同对象(或属于特定类的对象)使用缓存的信息时,我会这样做. 假设我得到字节码访问为

ObjectA
ObjectB
ObjectC
...

很容易找到物体的大小。我还可以通过这是对对象的第一次访问来确定对象的内存访问是否是内存分配。然后,假设 JVM 在运行时会分配连续的内存,我可以对缓存的使用情况做一个假设(通过运行缓存模拟)。现在,这不是一个很好的假设,但仍然给了我缓存使用的上限(至少我相信如此)。

4

2 回答 2

2

好吧,您总是可以通过艰难的方式做到这一点:更改虚拟机。有一些完全用 Java 编写的 JVM 实现,可以对其进行更改以收集您想要的数据。

但是,我坚信内存访问模式在很大程度上取决于运行程序的特定 VM(因为它们会以不同的方式在内存中组织数据)。不同的虚拟机 = 不同的访问模式。如果您在其中测量的 VM 具有 JIT,它还取决于 JIT 是否启动。

真正收集所有内存访问的方法是在某种沙盒环境中运行 VM 并计算其访问次数(这可以在某些模拟器中完成,或者在 MMU 的帮助下完成)。


编辑(问题更新 - 仅字节码检测):使用字节码检测,您基本上非常接近检测分析器所做的事情。您现在的主要问题是您无法轻松地在对象和内存地址之间建立关系。我可以想到两种方法来规避这个问题:

  • 有一个(JRE 私有,但可用)类 sun.misc.Unsafe可以为您获取对象、字段和数组的绝对内存地址(它有很多方法可以做到这一点)。如果您检测字节码以调用实用程序方法进行计数,它们可以使用 Unsafe 来确定将使用的地址。但是 Unsafe 是特定于实现的,垃圾收集器在堆周围移动对象可能会出现问题。这可能是也可能不是您想要衡量的。至少这可以通过合理的努力来实现。

  • 您可以完全放弃内存地址的概念,并将其替换为对象标识字段(分别为数组标识和索引)。然后,您的分析工具将需要跟踪对象和访问的字段。您真正需要注意的唯一一件事是您必须以不会阻塞垃圾收集器的方式保留对象引用(例如,使用 Wea​​kReferences)。这也不应该太难实现。这种方法不会识别热内存位置,而是识别热对象/字段

这两种方法都会对测量产生一些影响,因为收集到的数据将与正在分析的代码存储在同一个堆中。如果这是非常不可取的,您可以使用 JNI 来收集堆外数据。

于 2012-07-23T11:49:27.870 回答
0

Java 程序的哪一部分?Java“用户空间”由“public static void main(String[] args) {...”或整个 JVM 加载和先前可访问的类组成,其中包括幕后内存管理、垃圾收集、调试设施、管理设施等

如果您正在寻找真正的内存地址,那么您需要调试 JVM。这与调试 Java 程序有很大不同,因为在真实内存和“用户空间”程序之间存在内存抽象层。要调整实际内存访问,您无法重写 Java 程序,您需要重写 JVM。

字节码插入仍然是“用户空间”Java 程序的一部分,这意味着您将永远无法通过字节码插入确定绝对内存地址。事实上,对于同一个对象,JVM 引用到实际内存地址的“用户空间”映射甚至不会随着时间的推移保持不变。

于 2012-07-23T16:57:23.553 回答