Java对象地址提取和验证
出于某些研究目的,我想提取java对象的实际地址。需要明确的是,我实际上想要对象的48位虚拟地址,而不是ID或哈希代码或任何唯一标识符,我知道这些地址是由GC移动的。我一直在读stackoverflow的其他帖子,比如here或here
对于以下内容,我使用@Peter Lawrey -> Is there a way to get a reference address?方法。因此它使用Unsafe
类和arrayBaseOffset
方法。我发现这些方法的奇怪之处在于,它们每次运行(至少在我的计算机上)都会给出相同的结果,这是不太可能发生的。出于安全原因,内存分配应该是随机的
此外,我还尝试用Pintools验证这些方法,这是英特尔的检测工具,我用来提取运行的内存跟踪。我的问题是,我无法将Pintools的内存跟踪中看到的内容与上述方法给出的地址关联起来,以获得内存地址。我的内存跟踪中从未访问过给定的地址
所以我想知道这些方法返回了什么,以及这些结果是如何与其他工具进行验证的
一些信息:我的操作系统是Ubuntu x86_64,我的JVM是openJDK 64位1.8.0_131,pintools版本是v3。二,
=================== 大编辑:我意识到我的问题没有很好地表达出来,所以让我举一个更原子化的例子,下面是我试图分析的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);
}
}`
我从堆栈溢出上看到的不同方法中获得指向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]++;
}
}
通过这个pintools,我生成了一个内存跟踪+一个关于每个内存地址被访问多少次的历史记录。 注意:pintool是通过“follow_execv”选项启动的,以便为每个线程插入仪器
我看到两个问题:
1)我看不到任何打印的I地址(或接近此地址)的访问权限。我倾向于相信Pintools,因为我以前使用过很多,但也许Pintools无法在这里检索到正确的地址
2)我看不到地址被访问123次(或接近此次数)。我的想法是,可能JVM在这里执行优化,因为它看到执行的代码没有效果,所以它不会执行它。然而,我尝试在循环中使用更复杂的指令(不能像存储随机数那样进行优化),而不仅仅是存储到I,没有更好的结果
我不太关心GC效应,也许在第二步。我只希望能够从我的java应用程序中提取本机地址,我非常确定Pintools给了我这个应用程序
# 1 楼答案
我认为你应该提供更多关于你如何跑步以及你看到了什么的信息
要探索对象布局,可以使用http://openjdk.java.net/projects/code-tools/jol
使用这个工具,我得到了大致相同的结果:
通过这个例子http://hg.openjdk.java.net/code-tools/jol/file/018c0e12f70f/jol-samples/src/main/java/org/openjdk/jol/samples/JOLSample_21_Arrays.java,您可以测试数组上的GC影响
UPD
你提供了更多的信息,我当时试图帮助你。 第一次吸引了我的眼球
Java足够聪明,可以消除这个循环,因为结果总是一条指令“i=10;”。比如
将提供
正如你所见,你的方法和一个作业是一样的。另见: