- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
出于某些研究目的,我想提取 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.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/
我正在编写一个具有以下签名的 Java 方法。 void Logger(Method method, Object[] args); 如果一个方法(例如 ABC() )调用此方法 Logger,它应该
我是 Java 新手。 我的问题是我的 Java 程序找不到我试图用作的图像文件一个 JButton。 (目前这段代码什么也没做,因为我只是得到了想要的外观第一的)。这是我的主课 代码: packag
好的,今天我在接受采访,我已经编写 Java 代码多年了。采访中说“Java 垃圾收集是一个棘手的问题,我有几个 friend 一直在努力弄清楚。你在这方面做得怎么样?”。她是想骗我吗?还是我的一生都
我的 friend 给了我一个谜语让我解开。它是这样的: There are 100 people. Each one of them, in his turn, does the following
如果我将使用 Java 5 代码的应用程序编译成字节码,生成的 .class 文件是否能够在 Java 1.4 下运行? 如果后者可以工作并且我正在尝试在我的 Java 1.4 应用程序中使用 Jav
有关于why Java doesn't support unsigned types的问题以及一些关于处理无符号类型的问题。我做了一些搜索,似乎 Scala 也不支持无符号数据类型。限制是Java和S
我只是想知道在一个 java 版本中生成的字节码是否可以在其他 java 版本上运行 最佳答案 通常,字节码无需修改即可在 较新 版本的 Java 上运行。它不会在旧版本上运行,除非您使用特殊参数 (
我有一个关于在命令提示符下执行 java 程序的基本问题。 在某些机器上我们需要指定 -cp 。 (类路径)同时执行java程序 (test为java文件名与.class文件存在于同一目录下) jav
我已经阅读 StackOverflow 有一段时间了,现在我才鼓起勇气提出问题。我今年 20 岁,目前在我的家乡(罗马尼亚克卢日-纳波卡)就读 IT 大学。足以介绍:D。 基本上,我有一家提供簿记应用
我有 public JSONObject parseXML(String xml) { JSONObject jsonObject = XML.toJSONObject(xml); r
我已经在 Java 中实现了带有动态类型的简单解释语言。不幸的是我遇到了以下问题。测试时如下代码: def main() { def ks = Map[[1, 2]].keySet()
一直提示输入 1 到 10 的数字 - 结果应将 st、rd、th 和 nd 添加到数字中。编写一个程序,提示用户输入 1 到 10 之间的任意整数,然后以序数形式显示该整数并附加后缀。 public
我有这个 DownloadFile.java 并按预期下载该文件: import java.io.*; import java.net.URL; public class DownloadFile {
我想在 GUI 上添加延迟。我放置了 2 个 for 循环,然后重新绘制了一个标签,但这 2 个 for 循环一个接一个地执行,并且标签被重新绘制到最后一个。 我能做什么? for(int i=0;
我正在对对象 Student 的列表项进行一些测试,但是我更喜欢在 java 类对象中创建硬编码列表,然后从那里提取数据,而不是连接到数据库并在结果集中选择记录。然而,自从我这样做以来已经很长时间了,
我知道对象创建分为三个部分: 声明 实例化 初始化 classA{} classB extends classA{} classA obj = new classB(1,1); 实例化 它必须使用
我有兴趣使用 GPRS 构建车辆跟踪系统。但是,我有一些问题要问以前做过此操作的人: GPRS 是最好的技术吗?人们意识到任何问题吗? 我计划使用 Java/Java EE - 有更好的技术吗? 如果
我可以通过递归方法反转数组,例如:数组={1,2,3,4,5} 数组结果={5,4,3,2,1}但我的结果是相同的数组,我不知道为什么,请帮助我。 public class Recursion { p
有这样的标准方式吗? 包括 Java源代码-测试代码- Ant 或 Maven联合单元持续集成(可能是巡航控制)ClearCase 版本控制工具部署到应用服务器 最后我希望有一个自动构建和集成环境。
我什至不知道这是否可能,我非常怀疑它是否可能,但如果可以,您能告诉我怎么做吗?我只是想知道如何从打印机打印一些文本。 有什么想法吗? 最佳答案 这里有更简单的事情。 import javax.swin
我是一名优秀的程序员,十分优秀!