Java对象地址提取和验证

Java对象地址提取和验证,java,Java,出于某些研究目的,我想提取java对象的实际地址。需要明确的是,我实际上想要对象的48位虚拟地址,而不是ID或哈希代码或任何唯一标识符,我知道这些地址是由GC移动的。我一直在读stackoverflow的其他帖子 对于以下内容,我使用该方法。因此,它使用Unsafe类和arrayBaseOffset方法。我发现这些方法的奇怪之处在于,它们每次运行(至少在我的计算机上)都会给出相同的结果,这是不太可能发生的。出于安全原因,内存分配应该是随机的 此外,我还试图验证Intel的检测工具用于提取运行内存

出于某些研究目的,我想提取java对象的实际地址。需要明确的是,我实际上想要对象的48位虚拟地址,而不是ID或哈希代码或任何唯一标识符,我知道这些地址是由GC移动的。我一直在读stackoverflow的其他帖子

对于以下内容,我使用该方法。因此,它使用
Unsafe
类和
arrayBaseOffset
方法。我发现这些方法的奇怪之处在于,它们每次运行(至少在我的计算机上)都会给出相同的结果,这是不太可能发生的。出于安全原因,内存分配应该是随机的

此外,我还试图验证Intel的检测工具用于提取运行内存跟踪的方法。我的问题是,我无法将Pintools的内存跟踪中看到的内容与上述方法给出的地址关联起来,以获得内存地址。我的内存跟踪中从未访问过给定的地址

所以我想知道这些方法返回了什么,以及这些结果是如何与其他工具进行验证的

一些信息:我的操作系统是Ubuntu x86_64,我的JVM是openJDK 64位1.8.0_131,pintools版本是v3.2

=================== 大编辑:我意识到我的问题没有很好地表达出来,所以让我举一个更原子化的例子,下面是我试图分析的java:

`import sun.misc.Unsafe;
import java.lang.reflect.Field;

public class HelloWorld {

    public static void main(String[] args) throws Exception {
    Unsafe unsafe = getUnsafeInstance(); 
    Integer i = new Integer(42);
    long addr_fromArray;
    long addr_fromObject;

/////////////////////////////////////   
    Object[] objects = {i};
    long baseOffset = unsafe.arrayBaseOffset(Object[].class);
    addr_fromArray = unsafe.getLong(objects, baseOffset);   

    long factor1 = 8;        
    long addr_withFactor = (unsafe.getInt(objects, baseOffset) & 0xFFFFFFFFL) * factor1;

    /////////////////////////////////////   
    class Pointer {
        Object pointer;
    }

    Pointer pointer = new Pointer();
    pointer.pointer = i;
    long offset =     unsafe.objectFieldOffset(Pointer.class.getDeclaredField("pointer"));
    addr_fromObject = unsafe.getLong(pointer, offset);


    System.out.println("Addr of i from Array : 0x" + Long.toHexString(addr_fromArray));
    System.out.println("Addr of i from Object : 0x" + Long.toHexString(addr_fromObject));

    System.out.println("Addr of i from factor1 : 0x" + Long.toHexString(addr_withFactor));

    System.out.println("!=1");//Launch the pintools instrumentation 
    for(int a= 0 ; a < 123 ;a++){   
        i = 10;
    }
    System.out.println("!=1");//Stop the pintools instrumentation 
}

private static Unsafe getUnsafeInstance() throws SecurityException,
NoSuchFieldException, IllegalArgumentException,
IllegalAccessException {
    Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
    theUnsafeInstance.setAccessible(true);
    return (Unsafe) theUnsafeInstance.get(Unsafe.class);
    }
}`
`import sun.misc.Unsafe;
导入java.lang.reflect.Field;
公共类HelloWorld{
公共静态void main(字符串[]args)引发异常{
不安全=getUnsafeInstance();
整数i=新整数(42);
来自数组的长地址;
来自对象的长地址;
/////////////////////////////////////   
Object[]objects={i};
long baseOffset=unsafe.arrayBaseOffset(对象[].class);
addr_fromArray=unsafe.getLong(对象,baseOffset);
长系数1=8;
long addr_with factor=(unsafe.getInt(objects,baseOffset)&0xffffffffffffl)*factor1;
/////////////////////////////////////   
类指针{
对象指针;
}
指针指针=新指针();
pointer.pointer=i;
长偏移量=不安全的.objectFieldOffset(指针.class.getDeclaredField(“指针”));
addr_fromObject=unsafe.getLong(指针,偏移量);
System.out.println(“来自数组的i的Addr:0x”+长.toHexString(Addr\u fromArray));
System.out.println(“来自对象的i的地址:0x”+Long.toHexString(来自对象的地址));
System.out.println(“因子1中i的Addr:0x”+长.toHexString(Addr_with factor));
System.out.println(“!=1”);//启动pintools工具
对于(inta=0;a<123;a++){
i=10;
}
System.out.println(“!=1”);//停止pintools检测
}
私有静态不安全getUnsafeInstance()引发SecurityException,
NoSuchFieldException、IllegalArgumentException、,
非法访问例外{
字段theUnsafeInstance=Unsafe.class.getDeclaredField(“theUnsafeInstance”);
unsafeinstance.setAccessible(true);
返回(不安全)unsafeinstance.get(不安全的.class);
}
}`
我从堆栈溢出上看到的不同方法中获得指向I整数的指针。然后我在I上循环任意次数,这样我就可以在内存跟踪中识别它(注意:我检查了这段代码中没有发生GC调用)

当pintools看到标准输出中写入的特定“!=1”时,它启动/停止仪器

在检测阶段的每次访问中,我都执行以下代码:

VOID RecordAccess(VOID* ip, int id_thread , VOID * addr, int id)
{
    PIN_GetLock(&lock, id_thread);
    if(startInstru)
    {
        log1 << "Data accessed: " << addr << "\tThread:" << id_thread << endl;
        nb_access++;
        uint64_t dummy = reinterpret_cast<uint64_t>(addr);
        if(accessPerAddr.count(dummy) == 0)
            accessPerAddr.insert(pair<uint64_t,uint64_t>(dummy, 0));
        accessPerAddr[dummy]++;
    }
}
VOID记录访问(VOID*ip,int-id\u线程,VOID*addr,int-id)
{
销钉锁紧(锁紧,id锁紧螺纹);
if(startInstru)
{
日志1
因此,当我使用pintools检测此运行时,使用与此处类似的脚本。我没有看到对提到的地址或附近的地址执行任何访问

我认为你应该提供更多关于你如何跑步以及你看到了什么的信息

探索您可以使用的对象布局

通过这个示例,您可以测试阵列上的GC影响

UPD

你提供了更多的信息,我当时试图帮助你。 第一次吸引了我的目光

for(int a= 0 ; a < 123 ;a++){   
    i = 10;
}
如您所见,您的方法与一项作业相同。另请参见:

  • )
  • )

您可能希望在代码中包含“出于安全原因,内存分配应该是随机的”。您是否有任何参考资料,这在java中实际发生过?此语句在C中有一定意义,缓冲区溢出可能导致代码执行。如果这有帮助,请添加一些代码!@Bartoszbiliki:没错,我只是假设这是因为这是我在C/C++程序中看到的/因此可以解释确定性地址。它不能解释为什么我看不到此内存位置的内存访问,尽管你问的是0x76d1602b0->0x6c7204920->0x6c7204920在你的机器上不同的运行中是相同的,还是+-0x18偏移量?抱歉,你的回答,我意识到我不是pe非常清楚,所以我编辑了我的帖子,谢谢你的回答。很高兴看到这些方法已经与其他工具进行了对比。也许,Pintools不仅可以与Java应用程序正常工作,而且无法检索正确的地址我浏览了你的更新帖子并添加了信息。
Before GC
# WARNING: Unable to attach Serviceability Agent. Unable to attach even with escalated privileges: null
ascending: 76d430c7850, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
descending: 76d430e4850, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
shuffled: 76d43101850, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 

After GC
ascending: 6c782859856d88, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
descending: 6c78285e856eb8, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
shuffled: 6c782863856fe8, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 

After GC 2
ascending: 6c7828570548a8, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
descending: 6c78285c0549d8, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
shuffled: 6c782861054b08, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 

Process finished with exit code 0
for(int a= 0 ; a < 123 ;a++){   
    i = 10;
}
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.OperationsPerInvocation;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@State(Scope.Benchmark)
public class TestLoop {

    static final int _123 = 123;
    int TEN = 10;

    @Benchmark
    @OperationsPerInvocation(_123)
    public void oneAssigment() {
        Integer i = 1;
        i = 10;
    }

    @Benchmark
    @OperationsPerInvocation(_123)
    public Integer oneAssigmentAndReturn() {
        Integer i = 1;
        i = TEN;
        return i;
    }

    @Benchmark
    @OperationsPerInvocation(_123)
    public void doWrong() {
        Integer i = 1;
        for (int a = 0; a < _123; a++) {
            i = 10;
        }
    }

    @Benchmark
    @OperationsPerInvocation(_123)
    public void doWrongWithLocalVariable() {
        Integer i = -1;
        for (int a = 0; a < _123; a++) {
            i = TEN;
        }
    }

    @Benchmark
    @OperationsPerInvocation(_123)
    public Integer doWrongWithResultButOneAssignment() {
        Integer i = -1;
        for (int a = 0; a < _123; a++) {
            i = TEN;
        }
        return i;
    }

    @Benchmark
    @OperationsPerInvocation(_123)
    public void doWrongWithConstant(Blackhole blackhole) {
        for (int a = 0; a < _123; a++) {
            blackhole.consume(10);
        }
    }

    @Benchmark
    @OperationsPerInvocation(_123)
    public void doRight(Blackhole blackhole) {
        for (int a = 0; a < _123; a++) {
            blackhole.consume(TEN);
        }
    }

    public static void main(String[] args) throws Exception {
        new Runner(
                new OptionsBuilder()
                        .include(TestLoop.class.getSimpleName())
                        .warmupIterations(10)
                        .measurementIterations(5)
                        .build()
        ).run();
    }


}
Benchmark                                    Mode  Cnt             Score            Error  Units
TestLoop.doRight                            thrpt   50     352484417,380 ±    7015412,429  ops/s
TestLoop.doWrong                            thrpt   50  358755522786,236 ± 5981089062,678  ops/s
TestLoop.doWrongWithConstant                thrpt   50     345064502,382 ±    6416086,124  ops/s
TestLoop.doWrongWithLocalVariable           thrpt   50  179358318061,773 ± 1275564518,588  ops/s
TestLoop.doWrongWithResultButOneAssignment  thrpt   50   28834168374,113 ±  458790505,730  ops/s
TestLoop.oneAssigment                       thrpt   50  352690179375,361 ± 6597380579,764  ops/s
TestLoop.oneAssigmentAndReturn              thrpt   50   25893961080,851 ±  853274666,167  ops/s