2011-08-16 32 views
9

Có xem xét các tài liệu JNI đây: http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.htmlJNI EnsureLocalCapacity - TẠI SAO?

Cụ thể, nhìn vào những gì được nói trong các mô tả cho hàm EnsureLocalCapacity:

Đối với khả năng tương thích ngược, VM phân bổ tài liệu tham khảo địa phương ngoài bạn có đảm bảo sức chứa. (Là một sự hỗ trợ gỡ lỗi, VM có thể cung cấp cho các cảnh báo người dùng rằng quá nhiều tham chiếu cục bộ đang được tạo. Trong JDK, người lập trình có thể cung cấp tùy chọn dòng lệnh -verbose: jni để bật các thông báo này.) cuộc gọi FatalError nếu không có thêm địa phương tài liệu tham khảo có thể được tạo ra ngoài khả năng đảm bảo.

Và hơn nữa, hãy xem cách PushLocalFrame lấy đối số "dung lượng". (Và bằng cách nó không đề cập đến nếu đây là một giới hạn cứng, hoặc một giới hạn mềm như với EnsureLocalCapacity).

Trường hợp tất cả điều này vô nghĩa về khả năng tham chiếu cục bộ đến từ đâu? Các tài liệu nói rằng VM sẽ sẵn sàng phân bổ các tham chiếu vượt quá khả năng chính thức hiện tại, vậy tại sao nó không làm như vậy và giữ tất cả các khả năng này lộn xộn ra khỏi API?

Để đưa ra sự tương tự với C, có vẻ như tôi đang được yêu cầu lên kế hoạch trước bao nhiêu cuộc gọi malloc() tôi sẽ thực hiện và cảm thấy hơi vô lý.

Có điều gì quan trọng mà tôi không thấy ở đây không?

Trả lời

0

Đây là số đoán của tôi. Tôi nghi ngờ rằng việc tăng khả năng tham chiếu cục bộ là tốn kém và chức năng này cho phép yêu cầu dung lượng mong muốn một lần cho mỗi lần gọi phương thức gốc. Tôi nghĩ rằng điều này là nhiều hơn về hiệu suất hơn về tính chính xác.

0

Để hiểu kích thước bảng tham chiếu cục bộ của tôi được xác định trước và nếu bạn phân bổ nhiều hơn mức kích thước sẽ chỉ bị lỗi. Vì vậy, nó không phải là máy ảo sẽ cung cấp cho bạn nhiều refs địa phương mãi mãi. Tôi đã gặp phải điều này nhiều lần trong khi làm việc với JNI trên Android. Thường rất khó để tìm thấy rò rỉ bộ nhớ như vậy. Và gọi env-> DeleteLocalRef() mỗi lần bạn làm điều gì đó với các tham chiếu cục bộ JNI chỉ cần cắt mã. Vì vậy, thay vì làm lộn xộn mã bằng các cuộc gọi DeleteLocalRef(), chúng tôi chỉ có thể đảm bảo rằng chúng tôi không tạo quá nhiều tham chiếu và giữ mã hoàn toàn sạch sẽ. Và ngay cả khi chúng tôi dự định phân bổ nhiều tham chiếu địa phương hơn, chúng tôi vẫn có thể gọi PushLocalFrame()/PopLocalFrame() và tránh nhiều cuộc gọi đến DeleteLocalRef().

Vì vậy, để cung cấp cho bạn tương tự như "C", bạn được yêu cầu lên kế hoạch trước cuộc gọi của bạn để malloc để tránh tất cả các cuộc gọi cần thiết để miễn phí() ở cuối.

0

Tài liệu JNI mờ nhạt về chủ đề này. Tôi đã tìm thấy trong thực tế rằng tại lần số lượng refs địa phương có vẻ không bị chặn, nhưng bạn thực sự có thể chạy ra khỏi tài liệu tham khảo địa phương, ví dụ như khi iterating trên một mảng bằng cách sử dụng JNI cuộc gọi. Tham chiếu cục bộ là gì?Nó là một jobject (hoặc jarray, jstring, vv) mà bạn nhận được từ bất kỳ các nguồn:

  • trở về từ một JNI gọi thô như NewObjectV() hoặc GetObjectArrayElement()
  • trở về từ một gọi phương pháp như CallObjectMethodV()
  • qua chức năng mẹ đẻ của mình như một cuộc tranh cãi
  • có lẽ những người khác tôi đã quên

trong số này, bạn thường không cần lo lắng về các tài liệu tham khảo được truyền cho bạn trong một ar phương pháp gument, UNLESS bạn có ý định giữ tham chiếu xung quanh ngoài cuộc gọi phương thức hiện tại, trong trường hợp đó bạn nên chuyển đổi nó thành toàn cục.

Cần lưu ý rằng bạn không được tham gia một tham chiếu cục bộ nằm ngoài phạm vi phương pháp hiện tại. Nếu bạn định lưu trữ nó trong một đối tượng C++, bạn phải chuyển đổi nó thành global. Tham chiếu cục bộ có hai lợi thế

  1. Chúng luôn được tự động phát hành khi khung hiện tại nằm ngoài phạm vi.
  2. Họ là nhanh hơn so với chuyển đổi để toàn cầu

Giống như hầu hết các lỗi JNI, bất kỳ lạm dụng tài liệu tham khảo là khủng khiếp để chẩn đoán, vì vậy bạn thực sự không muốn để có được một. Phòng thủ tốt nhất của bạn là một cách tiếp cận nhất quán. Theo kinh nghiệm của tôi, chi phí chuyển đổi từ địa phương sang toàn cầu là khá nhỏ. Tôi sẽ đề nghị những điều sau đây, trừ khi bạn có nhu cầu thực hiện rất nghiêm ngặt.
Cho rằng, quy tắc của tôi là - LUÔN chuyển đổi refs địa phương để refs toàn cầu, sử dụng mã như:

jobject localjo = ... 
jobject globaljo = env->NewGlobalRef(localjo); 
env->DeleteLocalRef(localjo); 

Vào thời điểm đó, bạn có thể biết rằng mỗi ref là toàn cầu, và khi bạn làm xong, bạn cần để nhớ làm env-> DeleteGlobalRef (globaljo) trên mỗi cái. Trong C++, bạn có thể viết một lớp bao bọc xung quanh các tham chiếu JNI gọi env-> DeleteGlobalRef() trong dtor. Nhưng kể từ khi JNI không tham chiếu-đếm các tài liệu tham khảo JNI cho bạn, bạn có thể cần phải xây dựng nó trong là tốt.

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