2010-08-16 45 views
6

Tôi đang sử dụng bộ đệm trực tiếp (java.nio) để lưu trữ thông tin đỉnh cho JOGL. Các bộ đệm này lớn và chúng được thay thế nhiều lần trong suốt quá trình ứng dụng. Bộ nhớ không được deallocated trong thời gian và tôi đang hết bộ nhớ sau một vài thay thế.Xử lý bộ đệm gốc bộ đệm trực tiếp trong Java cho JOGL

Dường như không có cách nào tốt để giải quyết việc sử dụng lớp đệm của java.nio. Câu hỏi của tôi là:

Có phương pháp nào trong JOGL để xóa bộ đệm trực tiếp không? Tôi đang nhìn vào glDeleteBuffer(), nhưng nó có vẻ như thế này chỉ xóa bộ đệm từ bộ nhớ thẻ video.

Cảm ơn

Trả lời

0

deallocating một Buffer Direct là một công việc thực hiện bởi các nhà sưu tập rác một thời gian sau khi các đối tượng ByteBuffer được đánh dấu.

Bạn có thể thử gọi gc ngay lập tức sau khi xóa tham chiếu cuối cùng vào bộ đệm của bạn. Ít nhất có một cơ hội mà bộ nhớ sẽ được miễn phí một chút nhanh hơn.

+0

Bằng cách "gọi gc", bạn có nghĩa là 'System.gc()' tôi đoán; nó thực sự là một shot dài, như cuộc gọi đó không được đảm bảo để thực sự làm bất cứ điều gì. Hãy chắc chắn để đặt bất kỳ tham chiếu đến bộ đệm trực tiếp '= null' trước khi gọi đó, hoặc GC chắc chắn sẽ nghĩ rằng bộ đệm vẫn còn sử dụng. – Ricket

+0

Nhìn vào câu trả lời của tôi ... – gouessej

3

đệm trực tiếp là rất phức tạp và không có đảm bảo thu gom rác thải thông thường - xem để xem chi tiết hơn: http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#direct

Nếu bạn đang gặp vấn đề, tôi muốn đề nghị phân bổ một lần và tái sử dụng các bộ đệm chứ không phải phân bổ và deallocating nhiều lần.

+0

Đề xuất cuối cùng của bạn khá tốt. Bộ đệm thực sự hữu ích khi chúng được sử dụng nhiều lần. Có thể cắt chúng. Tuy nhiên, có nguy cơ làm tăng bộ nhớ bộ nhớ trong thời gian chạy bằng cách giữ bộ nhớ riêng được cấp phát không được sử dụng. Khi nó được thực hiện một cách chính xác, việc deallocation của bộ đệm NIO trực tiếp là hiệu quả hơn và ít xâm lấn hơn là cố gắng tránh phân bổ và deallocating chúng nhiều lần. – gouessej

0

Cách thức xử lý thỏa thuận được thực hiện khủng khiếp - tham chiếu mềm về cơ bản được chèn vào đối tượng Cleaner, sau đó thực hiện deallocation khi sở hữu ByteBuffer là thu thập rác. Nhưng điều này không thực sự đảm bảo được gọi đúng lúc.

+0

Bạn gọi nó là khủng khiếp, nhưng AFAIK nó là tốt như bạn có thể nhận được nó. Bộ đệm trực tiếp được cố ý phân bổ khỏi vùng quản lý nên chúng ta không nên ngạc nhiên bởi việc quản lý của chúng bị thiếu một chút. Dù sao, trước khi một OOM được ném ra, có những nỗ lực để xử lý tất cả các tài liệu tham khảo đang chờ giải quyết và GC được chạy. Nó có thể không hoạt động như thiết kế. +++ Tôi sợ, đó là tất cả những gì chúng tôi có thể trừ khi chúng tôi giải quyết vấn đề 'Không an toàn' và rủi ro malloc/miễn phí giống như rò rỉ và tai nạn. – maaartinus

7

Bộ đệm NIO trực tiếp sử dụng bộ nhớ không được quản lý. Nó có nghĩa là chúng được cấp phát trên heap gốc, không phải trên vùng heap Java. Kết quả là, chúng được giải phóng chỉ khi JVM hết bộ nhớ trên vùng heap Java, không phải trên heap gốc. Nói cách khác, nó không được quản lý = tùy thuộc vào bạn để quản lý chúng. Buộc việc thu gom rác bị nản chí và sẽ không giải quyết được vấn đề này phần lớn thời gian.

Khi bạn biết rằng bộ đệm NIO trực tiếp trở nên vô dụng đối với bạn, bạn phải giải phóng bộ nhớ riêng bằng cách sử dụng sun.misc.Cleaner (StaxMan là đúng) và gọi clean() (trừ Apache Harmony), gọi miễn phí() (với Apache Harmony) hoặc sử dụng API công khai tốt hơn để làm điều đó (có thể trong Java> = 1,9, AutoCleaning mở rộng AutoCloseable?).

Nó không phải công việc JOGL để làm điều đó, bạn có thể sử dụng mã Java đơn giản để tự làm điều đó. My example là theo GPL v2 và this example là theo giấy phép dễ dãi hơn.

Chỉnh sửa .: My latest example hoạt động ngay cả với Java 1.9 và hỗ trợ OpenJDK, Java Java, Sun Java, Apache Harmony, GNU Classpath và Android. Bạn có thể phải loại bỏ một số đường syntactical để làm cho nó hoạt động với Java < 1.7 (đa bắt, kim cương và generics).

tham khảo: http://www.ibm.com/developerworks/library/j-nativememory-linux/

đối tượng trực tiếp ByteBuffer dọn dẹp bộ đệm mẹ đẻ của họ tự động nhưng chỉ có thể làm như vậy như là một phần của Java đống GC - vì vậy họ không tự động ứng phó với áp lực lên đống bản địa.GC chỉ xảy ra khi vùng heap Java trở nên đầy, nó không thể đáp ứng yêu cầu phân bổ heap hoặc nếu ứng dụng Java yêu cầu một cách rõ ràng (không phải được đề xuất vì nó gây ra vấn đề về hiệu suất).

tham khảo: http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#direct

Nội dung của bộ đệm trực tiếp có thể cư trú bên ngoài đống rác-thu bình thường

This solution (trong JEP này, vẫn còn là một dự thảo, có lẽ không có sẵn trong Java 1.9) rất hứa hẹn, chúng tôi sẽ không cần sử dụng các API không công khai.

public long memory(long index) { 
    // The scope where the memory region is available 
    // Implements AutoClosable but `close` can be called manually as well 
    try (Scope scope = new NativeScope()) { 
     // Allocate the actual memory area, in this case in the style of a "long-array" 
     Pointer<Long> ptr = scope.allocate(
        NativeLibrary.createLayout(long.class), numElements); 

     // Get the reference to a certain element 
     Reference<Long> ref = ptr.offset(index).deref(); 

     // Set a value to this element through the reference 
     ref.set(Long.MAX_VALUE); 

     // Read the value of an element 
     return ref.get(); 
    } 
} 

NB: sun.misc.Cleaner đã được di chuyển vào jdk.internal.ref.Cleaner trong Java 1.9 trong module "java.base" nhưng cụ sau java.lang.Runnable (nhờ Alan Bateman đã nhắc nhở tôi rằng Sự khác biệt). Sau đó, bạn chỉ cần chuyển trình dọn dẹp sang Runnable và gọi phương thức run() (không gọi nó bằng cách phản ánh để tránh nhận một java.lang.IllegalAccessException). Nó hoạt động, tôi vừa thử nghiệm (tháng 8, 6, 2016) với Java 1.9 Truy cập sớm xây dựng 129.

Tuy nhiên, jdk.internal.ref.Cleaner có thể được chuyển đến java.ref.Cleaner $ Có thể xóa sau.

a good example in Lucene theo giấy phép dễ dãi hơn.

+0

+1: Điều này thực tế không liên quan đến 'JOGL' và tham chiếu tốt nhất tôi có thể tìm thấy ở đây khi phát hành bộ đệm java nio – Antoine

+0

Giải pháp cuối cùng trong danh sách của bạn có thể sẽ không sẵn sàng cho Java 9. JEP vẫn là một bản nháp . http://openjdk.java.net/jeps/191 – user833771

-1

Thay vì lạm dụng phản ánh của apis không công khai, bạn có thể làm điều này một cách tầm thường, hoàn toàn trong phạm vi công cộng được hỗ trợ.

Viết một số JNI kết thúc tốt đẹp malloc với NewDirectByteBuffer (nhớ đặt thứ tự) và một hàm tương tự để giải phóng nó.

+0

Tôi đồng ý với ochi và xem gợi ý cuối cùng trong bài đăng của tôi mà không sử dụng bất kỳ API không công khai nào. – gouessej

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