2008-12-03 27 views
22

Cách 'chính xác' để lưu trữ một con trỏ tự nhiên bên trong một đối tượng Java là gì?Cách 'chính xác' để lưu trữ một con trỏ tự nhiên bên trong một đối tượng Java là gì?

tôi có thể đối xử với con trỏ như một Java int, nếu tôi xảy ra cho biết rằng con trỏ bản địa là < = 32 bit về kích thước, hoặc Java long nếu tôi xảy ra cho biết rằng con trỏ bản địa là < = 64 bit trong kích thước. Nhưng liệu có cách nào tốt hơn hay sạch hơn để làm điều này?

Chỉnh sửa: Trả về con trỏ gốc từ hàm JNI chính xác là những gì tôi không muốn làm. Tôi thà trả về một đối tượng Java đại diện cho tài nguyên gốc. Tuy nhiên, đối tượng Java mà tôi trả về có lẽ có một trường có chứa một con trỏ, điều này đưa tôi trở lại câu hỏi ban đầu.

Hoặc, cách khác, có cách nào tốt hơn cho hàm JNI để trả lại tham chiếu đến tài nguyên gốc không?

+0

Liên quan chặt chẽ đến câu hỏi http://stackoverflow.com/questions/1632367/passing-pointers-between-c-and-java-through-jni – Raedwald

Trả lời

21

IIRC, cả hai java.util.zipjava.nio chỉ cần sử dụng long.

+1

+1. Sử dụng một thời gian dài, vì thời gian chạy Java tự thực hiện. – erickson

+0

sử dụng đối tượng kết thúc dài có phí: nó có thể tăng gấp đôi mức tiêu thụ bộ nhớ vì vỏ đối tượng có thể chiếm ít nhất 8 byte không đề cập đến trường hợp loại trình bao bọc của bạn sẽ phải thu gom rác –

2

Cách tốt hơn có thể bằng cách lưu trữ nó trong một mảng byte, vì con trỏ nguyên gốc không phải là Java-ish ở vị trí đầu tiên. int s và long s được bảo lưu tốt hơn để lưu trữ các giá trị số.

2

tôi cho rằng đây là một con trỏ trở về từ một số mã JNI và lời khuyên của tôi sẽ là chỉ không làm điều đó :)

Lý tưởng nhất là mã JNI nên vượt qua lại cho bạn một số loại tài liệu tham khảo hợp lý để các nguồn lực và không phải là một con trỏ thực tế?

Đối với câu hỏi của bạn, không có gì liên quan đến cách lưu trữ con trỏ - nếu bạn biết những gì bạn có thì hãy sử dụng int hoặc long hoặc byte [] theo yêu cầu.

+0

Bạn có thể đưa ra ví dụ về 'tham chiếu logic tới nguồn'? Tôi đã chỉnh sửa câu hỏi của mình để làm rõ những gì tôi có ý nghĩa một chút. –

+0

Tham chiếu lôgíc sẽ đơn giản là một số mã trả về jni được sử dụng trên các cuộc gọi subsewuent quay lại jni để tham khảo một cái gì đó. mã jni sau đó có thể dereference rằng thông qua một số loại cấu trúc, ví dụ một mảng [ref] [con trỏ]. hth – LenW

+1

Điều đó có nghĩa là duy trì một mảng chứa các con trỏ tới mọi tài nguyên cần được tham chiếu từ Java. Tôi không nghĩ đó là một ý tưởng hay ... –

0

Bạn có thể xem xét cách C# xử lý điều này bằng loại IntPtr. Bằng cách tạo kiểu của riêng bạn để giữ con trỏ, cùng một loại có thể được sử dụng dưới dạng 32 bit hoặc 64 bit tùy thuộc vào hệ thống bạn đang sử dụng.

3

Không có cách nào tốt. Trong SWT, mã này được sử dụng:

int /*long*/ hModule = OS.GetLibraryHandle(); 

và có công cụ chuyển đổi mã giữa 32 bit và 64 bit bằng cách di chuyển nhận xét. Xấu xí nhưng nó hoạt động. Mọi thứ sẽ dễ dàng hơn nhiều nếu Sun đã thêm một đối tượng "NativePointer" hoặc một cái gì đó như thế nhưng họ thì không.

3

java.nio.DirectByteBuffer thực hiện những gì bạn muốn.

Bên trong nó sử dụng một số private long address để lưu trữ giá trị con trỏ. Dah!

Sử dụng hàm JNI env->NewDirectByteBuffer((void*) data, sizeof(MyNativeStruct)) để tạo DirectByteBuffer trên mặt C/C++ và trả về bên Java làm ByteBuffer. Lưu ý: Đó là công việc của bạn để giải phóng dữ liệu này ở phía gốc! Nó bỏ lỡ trình dọn dẹp tự động có sẵn trên DirectBuffer chuẩn.

Tại phía Java, bạn có thể tạo một DirectByteBuffer theo cách này:

ByteBuffer directBuff = ByteBuffer.allocateDirect(sizeInBytes); 

nghĩ nó như là loại C của malloc(sizeInBytes). Lưu ý: Nó có chức năng Tự động làm sạch, giúp giải phóng bộ nhớ đã yêu cầu trước đó.

Nhưng có một số điểm cần xem xét về việc sử dụng DirectByteBuffer:

  • Nó có thể được thu gom rác (GC) nếu bạn bỏ lỡ tham khảo ByteBuffer trực tiếp của bạn.
  • Bạn có thể đọc/ghi các giá trị với cấu trúc nhọn, nhưng hãy cẩn thận với cả kích thước bù trừ và kích thước dữ liệu. Trình biên dịch có thể thêm các khoảng trống thừa cho việc đệm và phá vỡ các khoảng bù bên trong giả định của bạn trong cấu trúc. Cấu trúc với con trỏ (stride là 4 hoặc 8 byte?) Cũng câu đố dữ liệu của bạn.
  • ByteBuffers trực tiếp là rất dễ dàng để vượt qua như một tham số cho phương pháp bản địa, cũng như để có được nó trở lại như trở lại.
  • Bạn phải truyền để sửa loại con trỏ ở phía JNI. Loại mặc định được trả lại bởi env->GetDirectBufferAddress(buffer)void*.
  • Bạn không thể thay đổi giá trị con trỏ khi được tạo.
  • Công việc của bạn để giải phóng bộ nhớ trước đây được phân bổ cho bộ đệm ở phía gốc. Đó là những cái bạn đã sử dụng với env->NewDirectByteBuffer().
Các vấn đề liên quan