我想提取一些研究目的的java对象的实际地址。为了清楚起见,我实际上需要对象的48位虚拟地址,而不是ID或散列码或任何唯一标识符,并且我明白这些地址是由GC移动的。我一直在阅读其他帖子,比如here或here。Java对象地址提取和验证
对于以下我使用@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.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);
}
}`
我得到的指针我从堆栈溢出中看到的不同方法的整数。然后,我在一个循环中对任意数量的时间进行循环,以便我可以在我的记忆痕迹中识别出它(注意:我检查了此代码中没有发生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”选项启动的,以便测试每个线程。
我看到2个问题:
1)我认为没有访问到任何印刷我地址(或接近此地址)。我倾向于信任Pintools,因为我以前使用过很多,但也许Pintools无法在此处检索到正确的地址。
2)我看不到地址被访问123次(或接近此)。我的想法是,也许JVM在这里执行优化,因为它看到执行的代码没有效果,所以它不执行它。然而,我尝试了一个更复杂的指令(不能像存储一个随机数那样优化),而不仅仅是一个商店,而没有更好的结果。
我不在乎这里的GC效应,可能在第二步。我只想从我的Java应用程序中提取本地地址,我很确定Pintools给我的。
您可能想要包含您的代码 –
'由于安全原因,内存分配应该是随机分配的。'。你有任何参考这实际发生在Java?这个语句在C中有一定的意义,缓冲区溢出可能导致代码执行。 –
添加了一些代码,如果这有帮助! –