Я хотел бы извлечь фактический адрес java-объектов для какой-либо цели исследования. Чтобы быть ясным, мне действительно нужен виртуальный адрес 48 бит, а не идентификатор или хэш-код или какой-либо уникальный идентификатор, и я понимаю, что эти адреса перемещаются GC. Я читал другие сообщения из stackoverflow, например here или здесь.
Для следующего использования @Peter Lawrey → Есть ли способ получить ссылочный адрес?. Поэтому он использует класс Unsafe
с методом arrayBaseOffset
. То, что я нашел странным в этих методах, заключается в том, что они дают одинаковый результат для каждого запуска (по крайней мере, на моем компьютере), который вряд ли произойдет. Предполагается, что распределение памяти предполагается рандомизированным по соображениям безопасности.
Кроме того, я попытался проверить эти методы с помощью Pintools, который является инструментом инструментария от Intel, который я использовал для извлечения следов памяти прогона. Моя проблема в том, что я не могу сопоставить то, что я вижу в палитре памяти Pintools, с адресами, указанными вышеприведенными методами, для получения адресов памяти. Эти адреса никогда не доступны в моей памяти.
Итак, мне интересно, что возвращается этими методами и как эти результаты были проверены против других инструментов.
Некоторые сведения: моя ОС - Ubuntu x86_64, мой JVM - это openJDK 64bits 1.8.0_131, версия pintools v3.2
=================== Big Edit: Я понимаю, что мой вопрос не очень хорошо, так что позвольте мне получить более атомный пример, вот 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);
}
}`
Я получаю указатель на я Integer из разных методов, которые я видел при переполнении стека. Затем я делаю цикл на я в течение произвольного количества времени, чтобы распознать его в своей памяти (Примечание: я проверил, что в этом коде не происходит никаких вызовов 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 дает мне.