Tôi muốn trích xuất địa chỉ thực tế của các đối tượng java cho một số mục đích nghiên cứu. Chỉ cần rõ ràng, tôi thực sự muốn địa chỉ ảo 48bits của đối tượng, không phải ID hoặc mã băm hoặc bất kỳ mã định danh duy nhất nào và tôi hiểu rằng các địa chỉ đó được chuyển xung quanh bởi GC. Tôi đã đọc các bài đăng khác từ stackoverflow như here hoặc here.Khai thác địa chỉ đối tượng Java và xác minh
Đối với những điều sau, tôi sử dụng phương pháp @Peter Lawrey -> Is there a way to get a reference address?. Vì vậy, nó sử dụng lớp Unsafe
với phương thức arrayBaseOffset
. Những gì tôi thấy lạ về những phương pháp đó là họ đưa ra kết quả tương tự cho mỗi lần chạy (ít nhất là trên máy tính của tôi) mà rất khó xảy ra. Phân bổ bộ nhớ được cho là ngẫu nhiên vì lý do bảo mật.
Hơn nữa, tôi đã thử xác minh những phương pháp đó với Pintools là công cụ thiết bị đo đạc từ Intel mà tôi đã sử dụng để trích xuất các dấu vết bộ nhớ của chạy. Vấn đề của tôi là tôi không thể tương quan với những gì tôi thấy trong dấu vết bộ nhớ của Pintools với các địa chỉ được đưa ra bởi các phương thức trên để lấy địa chỉ bộ nhớ. Các địa chỉ đã cho không bao giờ được truy cập trong dấu vết bộ nhớ của tôi.
Vì vậy, tôi tự hỏi những gì được trả về bởi những phương pháp đó và cách những kết quả đó đã được xác minh nó so với các công cụ khác.
Một số infos: OS của tôi là một x86_64 Ubuntu, JVM của tôi là 64bits OpenJDK 1.8.0_131, pintools phiên bản v3.2
================ === Big Edit: tôi nhận ra rằng câu hỏi của tôi cũng không phải là đặt, vì vậy hãy để tôi có được một ví dụ nguyên tử hơn, đây là java mà tôi cố gắng phân tích:
`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);
}
}`
tôi nhận được con trỏ tới i Integer từ các phương thức khác nhau mà tôi đã thấy trên stack overflow. Sau đó, tôi lặp lại i trong một khoảng thời gian tùy ý để tôi có thể nhận ra nó trong dấu vết bộ nhớ của mình (Lưu ý: Tôi đã kiểm tra xem không có cuộc gọi GC nào xảy ra trong mã này)
Khi pintools thấy cụ thể "! = 1" ghi trong đầu ra tiêu chuẩn, nó bắt đầu/ngừng thiết bị đo đạc
trên mỗi truy cập trong giai đoạn thiết bị đo đạc, tôi thực thi mã này:
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]++;
}
}
với pintools này, tôi tạo ra một dấu vết bộ nhớ + một biểu đồ tần suất về cách nhiều lần mỗi địa chỉ bộ nhớ được truy cập. Lưu ý: pintool được khởi chạy với tùy chọn "follow_execv" để phát từng chuỗi.
Tôi thấy 2 Sự cố:
1) Tôi không thấy quyền truy cập vào bất kỳ địa chỉ in nào (hoặc gần địa chỉ này). Tôi có xu hướng tin tưởng Pintools vì tôi đã sử dụng khá nhiều trước đây nhưng có lẽ Pintools không thể truy xuất địa chỉ chính xác ở đây.
2) Tôi không thấy địa chỉ nào được truy cập 123 lần (hoặc gần với địa chỉ này). Suy nghĩ của tôi cho điều này là có lẽ JVM thực hiện tối ưu hóa ở đây vì nó thấy rằng mã được thực thi không có hiệu lực nên nó không thực thi nó. Tuy nhiên, tôi đã thử với một lệnh phức tạp hơn (không thể được tối ưu hóa như lưu trữ một số ngẫu nhiên) bên trong vòng lặp hơn là chỉ một cửa hàng cho i mà không có kết quả tốt hơn.
Tôi không quan tâm nhiều về hiệu ứng GC ở đây, có thể trong bước thứ hai. Tôi chỉ muốn có thể trích xuất các địa chỉ gốc từ ứng dụng java của mình mà tôi khá chắc chắn Pintools đang cho tôi.
Bạn có thể muốn bao gồm mã của mình –
'phân bổ bộ nhớ được cho là ngẫu nhiên vì lý do bảo mật'. Bạn có bất kỳ tham chiếu này thực sự xảy ra trong java? Câu lệnh này có ý nghĩa trong C, nơi tràn bộ đệm có thể dẫn đến việc thực thi mã. –
Đã thêm một số mã nếu điều này hữu ích! –