2011-12-11 28 views
19

JDK cung cấp khả năng cấp phát để phân bổ cái gọi là ByteBuffers trực tiếp, nơi bộ nhớ được cấp phát bên ngoài vùng heap Java. Điều này có thể có lợi vì bộ nhớ này không bị bộ thu gom rác chạm vào, và vì vậy không đóng góp cho GC overhead: đây là một đặc tính rất hữu ích cho những thứ tồn tại lâu dài như cache.Ví dụ về việc buộc giải phóng bộ nhớ gốc trực tiếp ByteBuffer đã cấp phát, sử dụng sun.misc.Unsafe?

Tuy nhiên, có một vấn đề nghiêm trọng với việc triển khai hiện tại: bộ nhớ cơ bản chỉ được phân bổ không đồng bộ khi ByteBuffer sở hữu được thu gom rác; không có cách nào để buộc tái phân bổ sớm. Điều này có thể có vấn đề vì bản thân chu trình GC không bị ảnh hưởng bởi việc xử lý ByteBuffers và cho rằng ByteBuffers có khả năng cư trú trong vùng bộ nhớ thế hệ cũ, có thể GC được gọi là giờ sau khi ByteBuffer không còn sử dụng nữa. Tuy nhiên, về mặt lý thuyết, có thể sử dụng phương thức sun.misc.Unsafe (freeMemory, allocateMemory) trực tiếp: đây là những gì JDK sử dụng để phân bổ/deallocating bộ nhớ riêng. Nhìn vào mã, một mối quan tâm tiềm năng mà tôi thấy là khả năng giải phóng bộ nhớ đôi - vì vậy tôi muốn đảm bảo rằng trạng thái sẽ được làm sạch đúng cách.

Có ai có thể chỉ cho tôi mã để thực hiện việc này không? Lý tưởng nhất là muốn sử dụng nó thay vì JNA.

LƯU Ý: Tôi đã thấy this question là loại có liên quan.

Có vẻ như các câu trả lời được chỉ ra là cách tốt để đi: here là ví dụ về mã từ Tìm kiếm đàn hồi sử dụng ý tưởng. Cảm ơn mọi người!

+0

Có thể, được tìm thấy trong trên SO năm trước ... tìm kiếm ngay bây giờ. (Trong quá khứ tôi đã kết thúc bằng cách sử dụng một hàng đợi hình tròn của bộ đệm, mà giữ áp suất thấp trong trường hợp của tôi.) –

+1

Wow, tôi không thể tìm thấy bất kỳ bài viết tốt bất cứ nơi nào ngay bây giờ: ( –

+0

Tôi chưa thấy một System.gc – nilskp

Trả lời

5

Sử dụng sun.misc.Unsafe là khó có thể vì địa chỉ cơ sở của bộ nhớ riêng được cấp phát là một biến cục bộ của java.nio.DirectByteBuffer constructor.

Trên thực tế bạn có thể buộc giải phóng bộ nhớ quê hương với đoạn mã sau:

import sun.misc.Cleaner; 

import java.lang.reflect.Field; 
import java.nio.ByteBuffer; 

... 

public static void main(String[] args) throws Exception { 
    ByteBuffer direct = ByteBuffer.allocateDirect(1024); 
    Field cleanerField = direct.getClass().getDeclaredField("cleaner"); 
    cleanerField.setAccessible(true); 
    Cleaner cleaner = (Cleaner) cleanerField.get(direct); 
    cleaner.clean(); 
} 
+0

Phải, đây là lý do tôi hỏi; toàn bộ dàn nhạc của Cleaner kết hợp với gọi lại đến Deallocator là phức tạp. Tôi sẽ thử phương pháp này, giả sử loại Cleaner có thể truy cập được (tôi nhận thấy rằng nó gọi là không). – StaxMan

2

Về cơ bản những gì bạn muốn tuân theo cùng ngữ nghĩa như sử dụng luồng IO. Cũng giống như bạn cần phải đóng một dòng một lần, bạn cần phải giải phóng bộ nhớ một lần. Vì vậy, bạn có thể viết wrapper của riêng bạn xung quanh các cuộc gọi bản địa làm sớm giải phóng bộ nhớ có thể

+0

Có, ở mức rất cao Đó là nơi mà các rắc rối bắt đầu: không có một phương pháp để làm điều đó với (trực tiếp) ByteBuffers, không có phương pháp close() Và ngay cả dưới mui xe, mọi thứ khá phức tạp, không may. – StaxMan

+0

Có nhưng bạn có thể thay đổi trò chơi bằng cách thực hiện bộ đệm của riêng bạn bằng cách sử dụng không an toàn. (Mà có thể hoạt động khá darn tốt với bộ nhớ đệm để tránh chia sẻ sai, nhưng đó là một trò chơi bóng hoàn toàn khác nhau) –

+0

Đúng, đủ. Và trong trường hợp của tôi, tôi hoàn toàn kiểm soát tất cả các truy cập, do đó, lưu trữ nguyên cơ bản không phải là tiếp xúc cũng không phải là nguy hiểm của tài liệu tham khảo lủng lẳng. – StaxMan

25

Có một cách đơn giản hơn nhiều để làm sạch bộ nhớ.

public static void clean(ByteBuffer bb) { 
    if(bb == null) return; 
    Cleaner cleaner = ((DirectBuffer) bb).cleaner(); 
    if (cleaner != null) cleaner.clean(); 
} 

Sử dụng nó có thể tạo sự khác biệt lớn nếu bạn loại bỏ trực tiếp hoặc bộ nhớ ánh xạ ByteBuffer khá nhanh.

Một trong những lý do để sử dụng Trình dọn dẹp để thực hiện việc này là bạn có thể có nhiều bản sao của tài nguyên bộ nhớ cơ bản, ví dụ: với slice(). và Trình dọn dẹp có số lượng tài nguyên.

+1

Hmmh. Tôi đã nhìn sạch hơn, nhưng không chắc chắn nếu quyền truy cập sẽ cho phép tôi gọi nó trực tiếp ... nhưng nếu vậy, điều này chắc chắn sẽ là một cách tốt để đi. Cảm ơn - có lẽ tôi đã quá vội vàng trong việc loại bỏ cách tiếp cận này! – StaxMan

+0

Tôi đã sử dụng phương pháp này trong một số dự án. Nó tốt hơn sử dụng IMHO phản chiếu. –

+0

Quyền - miễn là các lớp học có thể truy cập được, tôi đồng ý. Bản thân mã có thể được nạp tự động, nếu cần phải hỗ trợ trường hợp tiềm ẩn của Unsafe bị mất. Cảm ơn một lần nữa! – StaxMan

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