2009-06-18 28 views
9

Tôi nghĩ câu hỏi này sẽ được yêu cầu trước đó, nhưng tôi không thể tìm thấy nó ở đây ...Force Java để gọi C++ của tôi destructor (JNI)

Tôi đã sử dụng SWIG để tạo ra một wrapper JNI xung quanh một Lớp C++. Tất cả các công trình tuyệt vời ngoại trừ Java không bao giờ có vẻ gọi finalize của lớp(), do đó, lần lượt, destructor của lớp của tôi không bao giờ được gọi. Destructor của lớp làm một số tập tin cuối cùng I/O, vì vậy không may, đây không chỉ là một rò rỉ bộ nhớ nhỏ.

Tìm kiếm thông qua Google, có vẻ như không phải là cách để buộc Java vào GC và phá hủy một đối tượng. Thật?

Tôi biết tôi có thể thao tác tệp SWIG của mình và tạo một hàm java có thể gọi hàm hủy C++, nhưng lớp này được người dùng cuối sử dụng trong nhiều nền tảng/ngôn ngữ khác nhau, vì vậy việc bổ sung Java chỉ sẽ tạo sự mâu thuẫn mà các nhà văn công nghệ của chúng ta sẽ không thích.

Trả lời

7

Bạn không thể ép buộc GC bằng System.gc(). Ngoài ra nó không đảm bảo rằng sẽ có một GC chạy ví dụ nếu ứng dụng của bạn chỉ chạy trong một thời gian ngắn và sau đó finalizer của bạn sẽ không chạy ở tất cả (JVM không chạy nó khi thoát). Bạn nên tạo một hàm close() hoặc destroy() hoặc bất kỳ hàm nào cho lớp của bạn và khi bạn hoàn thành việc sử dụng một cá thể của lớp này, hãy gọi nó, tốt nhất là từ một khối cuối cùng, như thế nào.


MyClass x = null; 
try{ 
    x = new MyClass(); 
    x.work(); 
} finally { 
    if (x!=null) 
     x.close(); 
} 
5

Java finalizers hầu hết là vô ích, theo ý kiến ​​của tôi, và chắc chắn không phải là một sự thay thế cho C++ destructors. Thật không may, Java không có thay thế cho C++ RAII.

Đừng bận tâm đến việc cố gắng hoàn thành Java. Khi bạn đang đi qua với bất cứ điều gì, tất cả một chức năng sẽ xử lý nó. Đó là tất cả những gì bạn có thể làm.

0

Các vấn đề như vậy là lý do C# chọn mẫu IDisposable để xác định xác định.

Tôi đề nghị bạn làm theo cùng một mẫu và điều chỉnh nó cho người dùng Java của bạn.

Trong lớp C++ của bạn, hãy tạo một phương thức công khai riêng biệt phân phối tài nguyên của bạn. Gọi nó gần, hoặc vứt bỏ, hoặc cái gì đó.

Để trình gỡ lỗi C++ của bạn gọi phương thức công khai và báo cho người dùng được quản lý/GC của lớp C++ biết họ phải gọi phương thức để tránh rò rỉ bộ nhớ.

5

Nếu bạn đang dựa vào mã theo phương pháp finalize để chạy vào một thời điểm nhất định, bạn cần phải xem xét lại cách tiếp cận của mình. Vấn đề ở đây là bạn không biết khi nào finalize sẽ được gọi bởi JVM, vì bạn không biết khi nào đối tượng sẽ được thu gom rác. Một điều mà bạn nên cân nhắc, vì lớp của bạn sẽ được sử dụng lại trong các dự án khác, là có thể người dùng cuối có thể sử dụng một thể hiện của một lớp theo cách mà nó sẽ không được thu thập hoặc rằng việc thu gom rác sẽ khó xảy ra, chẳng hạn như tạo một tham chiếu tĩnh tới một thể hiện của lớp đó. Tôi nghĩ rằng việc tạo một phương thức close hoặc destroy là đặt cược an toàn nhất của bạn để đảm bảo rằng tài nguyên thể hiện của lớp C++ được liên kết với đối tượng Java của bạn đang được sử dụng được phát hành một cách thích hợp.

Kể từ khi tái sử dụng là một mối quan tâm, bạn có thể có destructor kiểm tra C++ để xem nếu các nguồn lực đã được phát hành và kêu gọi các mã tương tự nếu họ không được, như vậy:

class MyThing { 
    public: 
    void close(); 
    ~MyThing(); 

    private: 
    bool released = false; 
}; 

void 
MyThing::close() { 
    // close logic here 
    this->released = true; 
} 

MyThing::~MyThing() { 
    if (!released) { 
    this->close(); 
    } 
} 

Bằng cách này, mã C++ hiện tại của bạn hy vọng sẽ không phải thay đổi nhiều, và bạn có thể đảm bảo rằng các tài nguyên của bạn được phát hành theo cách xác định trong ngữ cảnh của mã gốc chạy qua JNI.

3

Sau khi tìm hiểu thêm về mã SWIG-sản xuất, tôi thấy rằng những người SWIG thực sự đã xử lý điều này - họ thêm một hàm delete() cho bạn. Nó trông khá tốt chăm sóc khả năng của cả hai lập trình viên và GC xóa đối tượng là tốt.

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