Có cách nào để giải phóng bộ nhớ trong Java, tương tự như free()
chức năng của C không? Hoặc là thiết lập đối tượng thành null và dựa vào tùy chọn duy nhất?
Có cách nào để giải phóng bộ nhớ trong Java, tương tự như free()
chức năng của C không? Hoặc là thiết lập đối tượng thành null và dựa vào tùy chọn duy nhất?
Câu trả lời:
Java sử dụng bộ nhớ được quản lý, vì vậy cách duy nhất bạn có thể phân bổ bộ nhớ là sử dụng new
toán tử và cách duy nhất bạn có thể phân bổ bộ nhớ là dựa vào trình thu gom rác.
Bản trắng quản lý bộ nhớ (PDF) này có thể giúp giải thích những gì đang diễn ra.
Bạn cũng có thể gọi System.gc()
để đề xuất rằng trình thu gom rác chạy ngay lập tức. Tuy nhiên, Java Runtime đưa ra quyết định cuối cùng, không phải mã của bạn.
Theo tài liệu Java ,
Gọi phương thức gc cho thấy Máy ảo Java dành nỗ lực tái chế các đối tượng không sử dụng để làm cho bộ nhớ mà chúng hiện đang chiếm dụng có sẵn để sử dụng lại nhanh chóng. Khi điều khiển trả về từ lệnh gọi phương thức, Máy ảo Java đã nỗ lực hết sức để lấy lại không gian từ tất cả các đối tượng bị loại bỏ.
System.gc()
hoàn toàn bỏ qua .
Dường như không ai đề cập đến việc thiết lập rõ ràng các tham chiếu đối tượng null
, đây là một kỹ thuật hợp pháp để "giải phóng" bộ nhớ mà bạn có thể muốn xem xét.
Ví dụ: giả sử bạn đã khai báo một List<String>
phần đầu của một phương thức có kích thước rất lớn, nhưng chỉ được yêu cầu cho đến khi đi được một nửa phương thức. Tại thời điểm này, bạn có thể đặt tham chiếu Danh sách null
để cho phép trình thu gom rác có khả năng lấy lại đối tượng này trước khi phương thức hoàn thành (và dù sao tham chiếu cũng nằm ngoài phạm vi).
Lưu ý rằng tôi hiếm khi sử dụng kỹ thuật này trong thực tế nhưng nó đáng để xem xét khi xử lý các cấu trúc dữ liệu rất lớn.
System.gc();
Chạy bộ thu gom rác.
Gọi phương thức gc cho thấy Máy ảo Java dành nỗ lực tái chế các đối tượng không sử dụng để làm cho bộ nhớ mà chúng hiện đang chiếm dụng có sẵn để sử dụng lại nhanh chóng. Khi điều khiển trả về từ lệnh gọi phương thức, Máy ảo Java đã nỗ lực hết sức để lấy lại không gian từ tất cả các đối tượng bị loại bỏ.
Không được khuyến khích.
Chỉnh sửa: Tôi đã viết phản hồi ban đầu vào năm 2009. Bây giờ là 2015.
Những người thu gom rác đã dần ổn định hơn trong khoảng 20 năm Java tồn tại. Tại thời điểm này, nếu bạn gọi thủ công trình thu gom rác, bạn có thể muốn xem xét các phương pháp khác:
* "Cá nhân tôi dựa vào các biến nulling như một trình giữ chỗ để xóa thích hợp trong tương lai. Ví dụ, tôi dành thời gian để vô hiệu hóa tất cả các phần tử của một mảng trước khi thực sự xóa (tạo null) chính mảng đó."
Điều này là không cần thiết. Cách thức hoạt động của Java GC là nó tìm thấy các đối tượng không có tham chiếu đến chúng, vì vậy nếu tôi có Object x có tham chiếu (= biến) a trỏ đến nó, thì GC sẽ không xóa nó, vì có một tham chiếu đến đối tượng đó:
a -> x
Nếu bạn null a hơn điều này xảy ra:
a -> null
x
Vì vậy, bây giờ x không có tham chiếu trỏ đến nó và sẽ bị xóa. Điều tương tự cũng xảy ra khi bạn đặt tham chiếu đến một đối tượng khác với x.
Vì vậy, nếu bạn có một mảng mảng tham chiếu đến các đối tượng x, y và z và một biến a tham chiếu đến mảng thì nó trông như thế:
a -> arr -> x
-> y
-> z
Nếu bạn null a hơn điều này xảy ra:
a -> null
arr -> x
-> y
-> z
Vì vậy, GC tìm thấy mảng là không có tham chiếu nào được đặt cho nó và xóa nó, nó cung cấp cho bạn cấu trúc này:
a -> null
x
y
z
Bây giờ, GC tìm thấy x, y và z và xóa chúng đi. Việc loại bỏ từng tham chiếu trong mảng sẽ không làm cho mọi thứ tốt hơn, nó sẽ chỉ sử dụng hết thời gian và không gian của CPU trong mã (có nghĩa là, nó sẽ không bị tổn thương nhiều hơn thế. GC vẫn có thể thực hiện theo cách nó nên ).
Một lý do hợp lệ cho việc muốn giải phóng bộ nhớ khỏi bất kỳ chương trình nào (java hay không) là để cung cấp thêm bộ nhớ cho các chương trình khác ở cấp hệ điều hành. Nếu ứng dụng java của tôi đang sử dụng 250MB, tôi có thể muốn giảm xuống còn 1 MB và cung cấp 249 MB cho các ứng dụng khác.
Để mở rộng câu trả lời và nhận xét của Yianni Xanthopoulos và Hot Licks (xin lỗi, tôi chưa thể bình luận!), Bạn có thể đặt các tùy chọn VM như ví dụ này:
-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30
Trong jdk 7 của tôi, điều này sau đó sẽ giải phóng bộ nhớ VM không sử dụng nếu hơn 30% heap trở nên miễn phí sau khi GC không hoạt động. Bạn có thể sẽ cần phải điều chỉnh các tham số này.
Mặc dù tôi không thấy nó được nhấn mạnh trong liên kết bên dưới, lưu ý rằng một số trình thu gom rác có thể không tuân theo các tham số này và theo mặc định java có thể chọn một trong số chúng cho bạn, nếu bạn tình cờ có nhiều hơn một lõi (do đó, đối số UseG1GC ở trên ).
Cập nhật: Đối với java 1.8.0_73, tôi đã thấy JVM thỉnh thoảng phát hành một lượng nhỏ với các cài đặt mặc định. Tuy nhiên, chỉ xuất hiện để làm điều đó nếu ~ 70% heap không được sử dụng .. không biết liệu nó có được phát hành mạnh hơn hay không nếu hệ điều hành thiếu bộ nhớ vật lý.
Tôi đã thực hiện thử nghiệm về điều này.
Đúng là System.gc();
chỉ đề xuất chạy Trình thu gom rác.
Nhưng gọi System.gc();
sau khi thiết lập tất cả các tham chiếu đến null
, sẽ cải thiện hiệu suất và chiếm dụng bộ nhớ.
Nếu bạn thực sự muốn phân bổ và giải phóng một khối bộ nhớ, bạn có thể thực hiện việc này với ByteBuffers trực tiếp. Thậm chí còn có một cách không di động để giải phóng bộ nhớ.
Tuy nhiên, như đã được đề xuất, chỉ vì bạn phải giải phóng bộ nhớ trong C, không có nghĩa là bạn nên làm điều này.
Nếu bạn cảm thấy bạn thực sự có một trường hợp sử dụng tốt miễn phí (), vui lòng bao gồm nó trong câu hỏi để chúng tôi có thể thấy những gì bạn đang muốn làm, rất có thể có một cách tốt hơn.
Hoàn toàn từ javacoffeebreak.com/faq/faq0012.html
Một chủ đề ưu tiên thấp sẽ tự động chăm sóc bộ sưu tập rác cho người dùng. Trong thời gian nhàn rỗi, luồng có thể được gọi và nó có thể bắt đầu giải phóng bộ nhớ trước đó cho một đối tượng trong Java. Nhưng đừng lo lắng - nó sẽ không xóa các đối tượng của bạn trên bạn!
Khi không có tài liệu tham khảo đến một đối tượng, nó trở thành trò chơi công bằng cho người thu gom rác. Thay vì gọi một số thói quen (như miễn phí trong C ++), bạn chỉ cần gán tất cả các tham chiếu cho đối tượng thành null hoặc gán một lớp mới cho tham chiếu.
Thí dụ :
public static void main(String args[]) { // Instantiate a large memory using class MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192); // Do some work for ( .............. ) { // Do some processing on myClass } // Clear reference to myClass myClass = null; // Continue processing, safe in the knowledge // that the garbage collector will reclaim myClass }
Nếu mã của bạn sắp yêu cầu một lượng lớn bộ nhớ, bạn có thể muốn yêu cầu trình thu gom rác bắt đầu lấy lại không gian, thay vì cho phép nó làm như một luồng ưu tiên thấp. Để làm điều này, thêm đoạn mã sau vào mã của bạn
System.gc();
Trình thu gom rác sẽ cố gắng lấy lại dung lượng trống và ứng dụng của bạn có thể tiếp tục thực thi, với càng nhiều bộ nhớ được lấy lại càng tốt (các vấn đề phân mảnh bộ nhớ có thể áp dụng trên một số nền tảng nhất định).
Trong trường hợp của tôi, vì mã Java của tôi có nghĩa là được chuyển sang các ngôn ngữ khác trong tương lai gần (Chủ yếu là C ++), tôi ít nhất muốn trả tiền dịch vụ môi để giải phóng bộ nhớ đúng cách để nó giúp quá trình chuyển tiếp sau này.
Cá nhân tôi dựa vào các biến nulling như một trình giữ chỗ để xóa thích hợp trong tương lai. Ví dụ, tôi dành thời gian để vô hiệu hóa tất cả các phần tử của một mảng trước khi thực sự xóa (tạo null) chính mảng đó.
Nhưng trường hợp của tôi rất đặc biệt và tôi biết tôi đang đạt được thành tích khi thực hiện điều này.
* "Ví dụ: giả sử bạn đã khai báo một Danh sách khi bắt đầu một phương thức có kích thước rất lớn, nhưng chỉ được yêu cầu cho đến khi đi được một nửa trong phương thức. Lúc này, bạn có thể đặt tham chiếu Danh sách thành null để cho phép trình thu gom rác có khả năng lấy lại đối tượng này trước khi phương thức hoàn thành (và dù sao tham chiếu cũng nằm ngoài phạm vi). " *
Điều này là chính xác, nhưng giải pháp này có thể không khái quát. Trong khi đặt tham chiếu đối tượng Danh sách thành null -will- cung cấp bộ nhớ cho bộ sưu tập rác, điều này chỉ đúng với đối tượng Danh sách các kiểu nguyên thủy. Nếu đối tượng Danh sách thay vì chứa các loại tham chiếu, việc đặt đối tượng Danh sách = null sẽ không hủy đăng ký -any- của các loại tham chiếu có trong danh sách. Trong trường hợp này, việc đặt đối tượng List = null sẽ mồ côi các loại tham chiếu có chứa đối tượng sẽ không có sẵn để thu gom rác trừ khi thuật toán thu gom rác đủ thông minh để xác định rằng các đối tượng đã mồ côi.
Java liên tục cung cấp bộ sưu tập rác tự động đôi khi bạn sẽ muốn biết đối tượng lớn bao nhiêu và còn lại bao nhiêu. Bộ nhớ miễn phí sử dụng theo chương trình import java.lang;
và Runtime r=Runtime.getRuntime();
để có được các giá trị của bộ nhớ sử dụng mem1=r.freeMemory();
để giải phóng bộ nhớ r.gc();
và gọifreeMemory()
Khuyến nghị từ JAVA là gán cho null
Từ https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html
Việc gán một giá trị null cho các biến không còn cần thiết sẽ giúp bộ thu gom rác xác định các phần của bộ nhớ có thể được thu hồi một cách an toàn. Mặc dù Java cung cấp quản lý bộ nhớ, nhưng nó không ngăn chặn rò rỉ bộ nhớ hoặc sử dụng quá nhiều bộ nhớ.
Một ứng dụng có thể gây rò rỉ bộ nhớ bằng cách không phát hành các tham chiếu đối tượng. Làm như vậy sẽ ngăn trình thu gom rác Java lấy lại các đối tượng đó và dẫn đến việc tăng lượng bộ nhớ được sử dụng. Hoàn toàn vô hiệu hóa các tham chiếu đến các biến sau khi sử dụng chúng cho phép trình thu gom rác lấy lại bộ nhớ.
Một cách để phát hiện rò rỉ bộ nhớ là sử dụng các công cụ định hình và chụp ảnh nhanh bộ nhớ sau mỗi giao dịch. Một ứng dụng không bị rò rỉ ở trạng thái ổn định sẽ hiển thị bộ nhớ heap hoạt động ổn định sau các bộ sưu tập rác.