如何在java中获取对象的内存位置?

sid*_*rma 27 java memory-management object

我想知道JVM分配给放置在系统内存中的对象的位置.

pru*_*nge 33

这是你可能不想做的事情.

如果你真的想这样做,像这样的代码可能会有所帮助:

package test;

import java.lang.reflect.Field;

import sun.misc.Unsafe;

public class Addresser
{
    private static Unsafe unsafe;

    static
    {
        try
        {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe)field.get(null);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static long addressOf(Object o)
    throws Exception
    {
        Object[] array = new Object[] {o};

        long baseOffset = unsafe.arrayBaseOffset(Object[].class);
        int addressSize = unsafe.addressSize();
        long objectAddress;
        switch (addressSize)
        {
            case 4:
                objectAddress = unsafe.getInt(array, baseOffset);
                break;
            case 8:
                objectAddress = unsafe.getLong(array, baseOffset);
                break;
            default:
                throw new Error("unsupported address size: " + addressSize);
        }       

        return(objectAddress);
    }


    public static void main(String... args)
    throws Exception
    {   
        Object mine = "Hi there".toCharArray();
        long address = addressOf(mine);
        System.out.println("Addess: " + address);

        //Verify address works - should see the characters in the array in the output
        printBytes(address, 27);

    }

    public static void printBytes(long objectAddress, int num)
    {
        for (long i = 0; i < num; i++)
        {
            int cur = unsafe.getByte(objectAddress + i);
            System.out.print((char)cur);
        }
        System.out.println();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 不能跨JVM或甚至不同版本移植
  • 对象可以随时因GC而移动,并且无法跨GC同步,因此结果可能没有意义
  • 没有在所有体系结构,endianess等测试,可能会使这在任何地方都无法正常工作

  • 即使启用了 UseCompressedOpps,64 位 Sun JDK 上的 `unsafe.addressSize()` 似乎也返回 8。使用在这种情况下返回 4 的 `unsafe.arrayIndexScale(Object[].class)` 似乎更有可能使用这种技术(毕竟,您将对象存储在 Object 数组中)。使用压缩 oops,返回的地址不是真正的地址 - 它可能会右移 3 位等。 (4认同)

tem*_*def 11

如果不使用特定于JVM的功能,则无法完成此操作.Java故意隐藏与每个对象关联的位置,以使实现具有更大的灵活性(JVM通常在执行垃圾收集时在内存中移动对象)并提高安全性(您不能使用原始指针来废弃内存或访问不存在的对象).

  • `Object.hashCode()` 不返回对象的内存地址。它是特定于实现的。我花了几个月的时间研究 JVM 的 JavaScript 实现,其中无法使用原始地址,并通过为每个对象递增一个计数器来实现“Object.hashCode()”。在某些实现上,这可能是“Object.hashCode()”的工作方式,但由于许多 JVM 在内存中移动对象,因此您不能相信这是真的。 (2认同)
  • `System.identityHashcode(Object)` 比返回对象的内存地址要复杂得多……即使它看起来就是这样做的。首先,即使 GC 移动了对象,它也必须返回相同的值。这通常需要“保存”对象中的值。(有些 JVM 以一种巧妙的方式做到这一点,最大限度地减少开销……但最终你还是要付出代价。) (2认同)