java - 由于任期空间的压缩,.hashcode() 会返回不同的 int 吗?

标签 java garbage-collection

如果我在某个对象上调用 Object.hashcode() 方法,它会返回该对象的内部地址(默认实现)。这个地址是逻辑地址还是物理地址?

在垃圾回收中,由于内存压缩,对象在内存中发生移动。如果我在 GC 之前和之后调用 hashcode,它会返回相同的 hashcode(它返回)吗?如果是,那么为什么(因为压缩地址可能会改变)?

最佳答案

@erickson 或多或少是正确的。 java.lang.Object.hashCode() 返回的哈希码在对象的生命周期内不会改变。

这种(通常)实现的方式相当聪明。当一个对象被垃圾收集器重新定位时,它的原始哈希码必须存储在某个地方,以防再次使用它。实现这一点的明显方法是在对象头中添加一个 32 位字段来保存哈希码。但这会给每个对象增加 1 个字的开销,并且在最常见的情况下会浪费空间......在不调用对象的 hashCode 方法的情况下。

解决方案是在对象的标志字中添加两个标志位,并(大致)如下使用它们。第一个标志是在调用 hashCode 方法时设置的。第二个标志告诉 hashCode 方法是使用对象的当前地址作为哈希码,还是使用存储的值。当 GC 运行并重定位对象时,它会测试这些标志。如果设置了第一个标志而未设置第二个标志,则 GC 在对象末尾分配一个额外的字并将原始对象位置存储在该字中。然后它设置两个标志。从那时起,hashCode方法从对象末尾的单词中获取hashcode值。


事实上,identityHashCode 实现必须以这种方式运行 以满足 general hashCode contract 的以下部分:

"Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application."

identityHashCode() 的假设实现仅返回对象的 当前 机器地址,如果/当 GC 将对象移动到另一个地址。解决这个问题的唯一方法是(假设的)JVM 保证对象一旦调用了 hashCode 就永远不会移动。这会导致严重且难以处理的堆碎片问题。

关于java - 由于任期空间的压缩,.hashcode() 会返回不同的 int 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3796699/

相关文章:

java - 如何在checkstyle中的 "excludedClasses"中设置默认+自己的类

java - 如何用日期实现空对象模式?

java - 如何确定flink中的任务槽数

java - Jelastic GC 代理不适用于 Tomcat 8.5.x

java - 如何找到哪些对象产生的垃圾最多

java - 在 Java 中自定义 catch block 并在 Eclipse 中启用智能插入

java - 如何刷新速度模板

java - System.gc 不会在单次运行中清除。使用 3 个或更多调用进行清算

c# - 将结构传递到接口(interface)字段是否分配?

java - 为什么不调用 finalize?