0

我试图找到一些近似值来解决堆问题,你们给了我这个函数System.IdentityHashCode(Object)

问题是 - 这个函数不适合原始类型。我会解释为什么。

我被作为输入 Java 编译程序 - 类文件。我的目标是绘制一些图表,其中将包含有关时间之间变量访问的一些信息。我事先不知道代码的外观,我的策略是为每个 LOAD 和 STORE 指令检测我自己的字节码。我正在使用 ASM Java 字节码检测。

因此,我不能做类似的事情:

identityHashCode(Integer.valueOf(...))

因为我不知道类型是 int、double、long 等。

我希望能够确定同一类的不同实例之间:

例如 :

class foo {
int a;
}
foo b;
foo c;
b.a++;
c.a++;

但是当涉及到字节码时,名称“b”/“c”与属性 a 之间没有关系。我“看到”的只是 a 增加了。两者都被视为一个!如果是这样,Object a 我可以使用 System.identityHashCode() 来区分它们。但我不能。

为了清楚起见,请看以下示例:

package manipulate;

public class Test {
        int c;
        public static void main(String[] args) {
            Test a=new Test();
            Test b=new Test();
            a.c++;
            b.c++;
        }
    }

它将被翻译(主函数)为以下字节码:

   L0
    LINENUMBER 7 L0
    NEW manipulate/Test
    DUP
    INVOKESPECIAL manipulate/Test.<init>()V
    ASTORE 1
   L1
    LINENUMBER 8 L1
    NEW manipulate/Test
    DUP
    INVOKESPECIAL manipulate/Test.<init>()V
    ASTORE 2
   L2
    LINENUMBER 9 L2
    ALOAD 1
    DUP
    GETFIELD manipulate/Test.c : I
    ICONST_1
    IADD
    PUTFIELD manipulate/Test.c : I
   L3
    LINENUMBER 10 L3
    ALOAD 2
    DUP
    GETFIELD manipulate/Test.c : I
    ICONST_1
    IADD
    PUTFIELD manipulate/Test.c : I
   L4
    LINENUMBER 11 L4
    RETURN

正如你所看到的,我在堆栈上得到的只是整数 c 的值。因此,鉴于该代码,我无法确定这两个 c 之间!

4

4 回答 4

4

基元没有身份。它们按值进行比较,而不是按引用进行比较。局部变量中原语在内存中的地址很可能在寄存器中或堆栈上,而数组或对象的原语成员的位置与其父级的堆地址有关。

Java 不提供任何标准化的内存访问设施,并且替代方案,如System.identityHashCode不扩展到它们。

使用原语调System.identityHashCode用将导致出现虚假装箱,这将产生无意义的结果。

如果你真的需要知道一个原始成员的位置,你可以编写带有 JNI 绑定的 C 代码来获取一个 java 对象的句柄,获取一个指针,并将其转换为正确宽度的 java 整数类型,但你最好打赌可能是找到其他方法来做你想做的事情。

另一种选择是使用现有的 java 调试器钩子:http: //download.oracle.com/javase/6/docs/technotes/guides/jpda/architecture.html#jdi

于 2011-02-25T19:24:54.263 回答
1

我所拥有的是 java 字节码。我没有 b 或 c,我不知道它们。我只有 a 的值在堆栈上

如果堆栈上有局部变量,则它们具有可变编号。这些数字对于方法正在执行的堆栈帧是本地的,如果两个变量具有相同的数字,则它们是相同的。

如果您的评估(参数/操作数/结果)堆栈中有两个原始值,如果它们同时存在于相同的堆栈索引中,它们是相同的(与变量的意义相似)。


在您的示例中,您看到两条GETFIELD manipulate/Test.c : I指令分别对堆栈上的当前值进行操作(由ALOAD 1or放在那里ALOAD 2)。此当前值是您的变量所属的对象,因此您可以在其中插入该对象的计数代码(首先执行 DUP)。

于 2011-02-25T19:46:31.507 回答
0

我不确定我是否理解这个问题,您想知道 ba 是否实际上与 ca 相同?

在您的情况下,如果 b==c,ba 将与 ca 相同。如果您声明一个静态,它将在 foo 的所有实例之间共享。

于 2011-02-25T19:29:25.970 回答
0

当您询问内存地址并得到 identityhashCode 答案时,关键短语是“一些近似值”。不能保证这个值就是内存地址,甚至最激进的断言是它是从地址到整数的映射。您绝对不能可靠地确定 Java 中对象的地址,甚至不应该考虑尝试使用原语。一方面,不能保证编译器不会移动它们。甚至不能保证该变量曾经有一个地址。

如果要判断两个对象是否相同,可以使用“==”。这个问题甚至对原语都没有意义,你不应该这样做。

于 2011-02-25T19:36:38.460 回答