使用Java在内存中定位对象?

时间:2011-04-28 22:06:17

标签: java

3 个答案:

答案 0 :(得分:6)

通常,在Java中,identityHashCode()函数没有指定任何有关内存地址的内容。唯一指定的是这些数字在对象的整个生命周期内是恒定的,并且它们对于不同的对象尽可能不同

  • 在具有足够内存的64位虚拟机上,您可以同时创建超过2 ^ 32个对象,因此即使是第二个条件也不能表示“对于不同的对象始终不同”。

  • 现代Sun虚拟机正在使用分代垃圾收集器,这意味着对象在其生命周期内被移动。然后内存地址会发生变化,而身份哈希码必须相同 - 因此它不能总是内存地址。

因此,除了上述条件之外,你不能依赖任何东西。 在一些VM(特别是具有非移动垃圾收集器的旧VM)上,该数字可能是可以在C中转换为内存地址(或创建对象时的初始地址),但另一个有效的实现将是伪随机的在对象创建或简单计数器上给出的数字。

答案 1 :(得分:2)

我是那个建议OP应该使用identityHashcode()值作为 ersatz 内存地址的人。我的想法是,虽然它们不是真正的内存地址,但它们基于第一次调用identityHashcode()时所讨论的对象的内存地址...在典型的JVM实现上。这使得它们成为实际内存地址的合理代理,用于此实验。

我对OP的回答是,这些结果强烈暗示ASLR未启用,或者无法随机化Java对象的实际地址。

由于JVM引导序列中的非确定性因素,我预计对象地址会有一定的自然不可预测性。这就是为什么您在不同的运行中看到该对象的3或4个不同的哈希码值。但是,您反复看到某些值的事实强烈表明没有系统的随机化发生。换句话说,没有ASLR。

严格地说,我们应该检查JVM源代码,检查identityHashcode是否真的报告了如果ASLR生效,更改的内容......但我没有时间现在


(FWIW:我同意其他人回答/评论说Java不需要ASLR。在JVM本机代码中修改了一些未修补的bug,Java JVM根本不允许沙盒Java程序注入可执行文件(即使是特权Java程序也只能通过自定义本机库来实现。)

答案 2 :(得分:1)

地址空间布局随机化(ASLR)是:

  • 对于Java应用程序不是必需的
  • 对Java应用程序不太有帮助
  • 积极地被许多JVM实现的内存管理技术所击败
例如,Sun的JVM将在启动时分配大部分虚拟内存(可能使用操作系统堆函数来获取单个大块),然后继续将该内存作为自己的堆进行管理已知的方式。也就是说,Eden,Survivor空间,Tenured堆和PermGen都以同样的方式布局,我很确定ASLR对此无能为力。

然而,ASLR试图阻止的黑客攻击技术无论如何都无法在Java中实现,原因如下:

  1. 大多数JVM实现经常将对象从一个位置复制到内存中的另一个位置。因此,无法确切地预测任何物体在任何时间点的位置。

  2. Java代码无法在Java堆栈上分配任意大小的对象,因此无法进行堆栈溢出。

  3. 不可能从Java代码中破坏Java内存模型;可能的唯一代码是通过JNI调用的平台本机代码。 (或sun.misc.Unsafe,这是一个基本相同的不安全的包装器。)因此,只要您正确使用Java SecurityManager功能,没有恶意进程能够写入任何< / em>无论如何危险的记忆位置。

  4. 也许你应该描述你想要完成的事情,以及为什么你认为ASLR会帮助你完成它。我很确定(a)ASLR对你的Java程序没有任何影响,并且(b)没关系,因为你无论如何都不想要它。