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