2011-10-28 28 views
6

Tôi đang cố gắng để hiểu tài liệu của sun.misc.Unsafe - Tôi đoán vì nó không dành cho mục đích sử dụng chung, không ai thực sự làm phiền với việc làm cho nó dễ đọc - nhưng tôi thực sự cần một cách để tìm địa chỉ của một phần tử trong một mảng (để tôi có thể chuyển một con trỏ tới nó tới mã gốc). Có ai có bất kỳ mã làm việc nào không? Nó có đáng tin cậy không?Sử dụng sun.misc.Unsafe để lấy địa chỉ của các mục Java array?

+0

http://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe –

+0

[Lý do nhà phát triển không nên viết chương trình Gói gọi 'mặt trời' đó] (http://www.oracle .com/technetwork/java/faq-sun-packages-142232.html) – BalusC

+0

imo, tài liệu không an toàn là khá tốt, nó không dành cho anyways công chúng nói chung. nếu bạn cần một số hướng dẫn, bắt đầu đọc java.util.concurrent và java.util.concurrent.atomic ... không an toàn là khá gần với C (hoặc assembler, nếu bạn thích). Nếu bạn không có kinh nghiệm nếu có, không an toàn không dành cho bạn. Làm thế nào để có được tháo rời mã java của bạn: http://wikis.sun.com/display/HotSpotInternals/PrintAssembly – bestsss

Trả lời

6

Thay vì sử dụng mảng, bạn có thể sử dụng bộ đệm trực tiếp ByteBuffer.allocateDirect(). Điều này có địa chỉ trong một lĩnh vực và địa chỉ này không thay đổi cho cuộc sống của ByteBuffer. Một ByteBuffer trực tiếp sử dụng không gian heap tối thiểu. Bạn có thể lấy địa chỉ bằng cách sử dụng sự phản chiếu.


Bạn có thể sử dụng Unsafe để nhận địa chỉ, vấn đề là GC có thể di chuyển nó bất cứ lúc nào. Các đối tượng không được cố định trong bộ nhớ. Trong JNI, bạn có thể sử dụng các phương pháp đặc biệt để sao chép dữ liệu đến/từ các đối tượng Java để tránh vấn đề này (và những người khác). Tôi khuyên bạn nên sử dụng chúng nếu bạn muốn trao đổi dữ liệu giữa các đối tượng với mã C.

+1

Tôi không muốn sử dụng bộ đệm byte trực tiếp (điều này sẽ giúp giải quyết vấn đề khá dễ dàng) vì tôi đang cố gắng triển khai API hiện tại được xác định theo mảng byte và đang cố tránh hình phạt sao chép và từ bộ bộ đệm bổ sung. Điều này sẽ đủ như một phương sách cuối cùng, nhưng phải có một số cách tốt hơn. Làm việc với JNI sẽ làm cho việc này trở nên dễ dàng hơn, nhưng tiếc là tôi đang làm việc với JNA, dường như không có giao diện cần thiết để làm bất cứ điều gì ngoài làm việc với toàn bộ mảng. – Jules

+0

@Jules, JNI sẽ tự tạo một bản sao, trừ khi bạn muốn truy cập w/'GetPrimitiveArrayCritical' có thể làm tổn thương GC. Cắn viên đạn và sao chép vào bộ nhớ trực tiếp (bộ đệm). Đó là giải pháp khả thi duy nhất. Ví dụ như impl. FileOutputStream (SocketOutputStream mở rộng nó) sử dụng bản sao của các phần tử trên ngăn xếp. Hình phạt để sao chép không quá cao, vì chi phí cao nhất đến w/chi phí tải của dữ liệu (và bộ nhớ cache bị mất, thậm chí) mà bạn sẽ phải trả một trong hai cách. Việc sao chép cũng sẽ gây ra việc tìm nạp trước các đường dẫn trong bộ nhớ cache, do đó, nó có thể thậm chí còn tốt hơn làm cách nào mã nguồn gốc hoạt động. – bestsss

+0

@Jules, trên một lưu ý phụ: thậm chí javax.net.ssl.SSLEngine cho phép sử dụng bộ đệm, tất cả các thuật toán là byte [] và chúng kết thúc sao chép bộ đệm trực tiếp vào mảng tạm thời, đây là câu chuyện ngược lại và đạo đức của nó : không sử dụng bộ đệm trực tiếp w/SSLEngine. – bestsss

6

Đây là mẫu đang hoạt động. Tuy nhiên, hãy cẩn thận vì bạn có thể dễ dàng phá vỡ JVM của mình bằng cách sử dụng không phù hợp lớp Unsafe.

import java.lang.reflect.Field; 

import sun.misc.Unsafe; 

public class UnsafeTest { 

    public static void main(String... args) { 
     Unsafe unsafe = null; 

     try { 
      Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); 
      field.setAccessible(true); 
      unsafe = (sun.misc.Unsafe) field.get(null); 
     } catch (Exception e) { 
      throw new AssertionError(e); 
     } 

     int ten = 10; 
     byte size = 1; 
     long mem = unsafe.allocateMemory(size); 
     unsafe.putAddress(mem, ten); 
     long readValue = unsafe.getAddress(mem); 
     System.out.println("Val: " + readValue); 

    } 
} 
+2

Mã đó phải hoàn toàn an toàn, vì đó chính là cách thức hoạt động của DirectByteBuffer. Thật không may, nó không làm những gì tôi muốn, đó là để truy cập dữ liệu trong một mảng hiện có. – Jules

+4

@StephenC, mã hoàn toàn ổn, về cơ bản nó là 'char * mem = malloc (kích thước); ...' nó không bao giờ được chạm vào bởi GC và gây ra rò rỉ C bản địa trừ khi được thực hiện. – bestsss

+2

Mã là tốt, nhưng bạn cũng cần cân nhắc giải phóng bộ nhớ được cấp phát. Xem DirectByteBuffer để biết cách thực hiện. Cũng xem xét rằng bộ nhớ phân bổ không phải là zeroed, vì vậy bạn không thể giả định mảng trực tiếp của bạn là không được khởi tạo. –

1

Tại sao? Có rất nhiều cơ sở trong JNI để xử lý các nội dung của các mảng Java. Bạn không cần phải sử dụng các lớp Sun nội bộ không có giấy tờ mà có thể không có ở tuần tới.

+0

Tôi đang sử dụng JNA, chứ không phải JNI, và chức năng tôi đang giao tiếp với các nhu cầu để có một con trỏ được chuyển đến giữa một mảng, trong khi JNA chỉ xuất hiện để có thể tạo ra một con trỏ đến đầu của một mảng. – Jules

+0

@Jules, không trộn lẫn các mảng JNA và bình thường, sử dụng bộ đệm trực tiếp. – bestsss

Các vấn đề liên quan