gpt4 book ai didi

Java对象地址提取和验证

转载 作者:搜寻专家 更新时间:2023-10-30 21:12:16 28 4
gpt4 key购买 nike

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

对于以下内容,我使用 @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);
}
}`

我从在堆栈溢出时看到的不同方法获得了指向 i Integer 的指针。然后我在 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”选项启动的,以便检测每个线程。

我看到 2 个问题:

1) 我看不到任何打印的 i 地址(或靠近该地址)的访问。我倾向于信任 Pintools,因为我以前使用过很多,但 Pintools 可能无法在此处检索到正确的地址。

2) 我没有看到任何地址被访问 123 次(或接近此次数)。我对此的想法是,也许 JVM 在这里执行优化,因为它看到执行的代码没有效果,所以它不执行它。但是,我尝试在循环内使用更复杂的指令(无法像存储随机数那样进行优化),而不仅仅是存储到 i 而没有更好的结果。

我不太关心这里的GC效果,可能在第二步。我只希望能够从我的 Java 应用程序中提取 native 地址,我很确定 Pintools 会提供给我。

最佳答案

So when I am instrumenting this run with pintools, with a similar script as here . I don't see any access performed on the mentionned addresses or nearby addresses

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

要探索对象布局,您可以使用 http://openjdk.java.net/projects/code-tools/jol .

import org.openjdk.jol.info.GraphLayout;

import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.SortedSet;

public class OrderOfObjectsAfterGCMain2 {
public static void main(String... args) {
Double[] ascending = new Double[16];
for (int i = 0; i < ascending.length; i++)
ascending[i] = (double) i;

Double[] descending = new Double[16];
for (int i = descending.length - 1; i >= 0; i--)
descending[i] = (double) i;

Double[] shuffled = new Double[16];
for (int i = 0; i < shuffled.length; i++)
shuffled[i] = (double) i;
Collections.shuffle(Arrays.asList(shuffled));

System.out.println("Before GC");
printAddresses("ascending", ascending);
printAddresses("descending", descending);
printAddresses("shuffled", shuffled);

System.gc();
System.out.println("\nAfter GC");
printAddresses("ascending", ascending);
printAddresses("descending", descending);
printAddresses("shuffled", shuffled);

System.gc();
System.out.println("\nAfter GC 2");
printAddresses("ascending", ascending);
printAddresses("descending", descending);
printAddresses("shuffled", shuffled);

}

public static void printAddresses(String label, Double[] array) {
PrintWriter pw = new PrintWriter(System.out, true);
pw.print(label + ": ");
// GraphLayout.parseInstance((Object) array).toPrintable() has more info
SortedSet<Long> addresses = GraphLayout.parseInstance((Object) array).addresses();
Long first = addresses.first(), previous = first;
pw.print(Long.toHexString(first));
for (Long address : addresses) {
if (address > first) {
pw.print(Long.toHexString(address - previous) + ", ");
previous = address;
}
}
pw.println();
}

使用这个工具我得到了大致相同的结果:

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

用这个例子http://hg.openjdk.java.net/code-tools/jol/file/018c0e12f70f/jol-samples/src/main/java/org/openjdk/jol/samples/JOLSample_21_Arrays.java您可以测试 GC 对数组的影响。

更新

您提供了更多信息,当时我已尽力为您提供帮助。首先映入眼帘的是

for(int a= 0 ; a < 123 ;a++){   
i = 10;
}

Java 足够聪明,可以消除这个循环,因为结果总是 - 一条指令“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

如您所见,您的方法与一次作业相同。另见:

关于Java对象地址提取和验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45503528/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com