/Garbage Collection trong Java có gì đáng chú ý?

Garbage Collection trong Java có gì đáng chú ý?

Trong Java, rác (garbage) có nghĩa là các đối tượng không còn được tham chiếu và bộ thu gom rác (garbage collection) được sử dụng để thực hiện quá trình tự động khôi phục lại bộ nhớ. Nói cách khác, đó là một cách để phá hủy các đối tượng không sử dụng nữa.

Vậy Garbage Collection trong Java có điểm gì đáng chú ý? Hãy cùng Quản Trị Mạng tìm hiểu về khái niệm của Garbage Collection, cách thức hoạt động và tại sao nó lại quan trọng trong bài viết này nhé!

1. Khái niệm về Garbage Collection

Garbage Collection (Bộ thu gom rác) trong Java được định nghĩa như một quá trình tự động thực thi nhiệm vụ quản lý bộ nhớ.

Code Java được dịch sang bytecode rồi chạy trên máy ảo Java hay viết tắt là JVM. Trong quá trình chạy chương trình, các đối tượng được tạo ở vùng nhớ heap, một phần bộ nhớ dành cho chương trình. Sau cùng, sẽ có một vài đối tượng mà chương trình không cần dùng đến. Các đối tượng này sẽ được garbage collector truy tìm và xóa bỏ để thu hồi lại dung lượng bộ nhớ.

Không gian trống này sẽ được cấp phát cho những đối tượng mới. Với các ngôn ngữ lập trình như C, việc giải phóng bộ nhớ được thực hiện một cách thủ công (bằng những lệnh khởi tạo, giải phóng bộ nhớ). Với Java, việc giải phóng bộ nhớ được thực hiện một cách tự động.

2. Garbage collection trong Java hoạt động như thế nào?

Garbage Collection trong Java là một quá trình hoàn toàn tự động. Các lập trình viên không cần gọi các lệnh “dọn” bộ nhớ như trong ngôn ngữ lập trình C/ C++. Phần hệ thống xử lý của garbage collection nằm trong JVM. Mỗi JVM lại có một cách cài đặt bộ dọn rác khác nhau, phù hợp với những đặc tính của JVM đó. Trong số các đại diện JVM, Oracle HotSpot sẽ được chúng tôi lấy ra làm ví dụ vì nó đang được sử dụng phổ biến nhất và bộ dọn rác của HotSpot có nhiều tính năng mạnh mẽ hơn so với những người anh em khác.

HotSpot có nhiều bộ dọn rác nhưng tựu chung lại các bộ dọn rác này đều hoạt động theo mô hình chung. Đầu tiên, xác định và đánh dấu các đối tượng không có tham chiếu (unreferenced object) sẵn sàng để thu gom rác. Bước thứ hai, xóa các đối tượng đã được đánh dấu. Tùy chọn, bộ nhớ có thể được “nén” lại sau khi bộ garbage collector tiến hành xóa các đối tượng, điều này đồng nghĩa với việc các đối tượng đang hoạt động sẽ nằm ở các ô nhớ sát nhau tại phần bắt đầu của heap. Quá trình “nén” này giúp cấp phát bộ nhớ cho các đối tượng mới dễ dàng hơn sau khi khối bộ nhớ được phân bổ cho các đối tượng hiện có.

Tất cả các garbage collector của HotSpot thực hiện theo một chiến thuật chung là chia đối tượng theo “tuổi hoạt động”. Lý do đằng sau việc chia bộ thu dọn rác theo tuổi hoạt động là vì hầu hết các vật thể đều tồn tại trong thời gian ngắn và sẽ sẵn sàng thu gom ngay sau khi tạo ra.

3. Lợi ích của garbage collection trong Java
Lập trình C/ C++ chắc hẳn đã từng gặp khó khăn khi đương đầu với Memory Leaks. Tuy nhiên, với Java nói riêng và các ngôn ngữ sở hữu Garbage Collector, cực hình này đã được chấm dứt hoàn toàn.

Trong khi giới lập trình vẫn đang tranh cãi về khả năng hoạt động hiệu quả của Garbage Collector và phe bảo thủ một mực khẳng định rằng việc quản lý bộ nhớ bằng tay sẽ mang lại khả năng kiểm soát và hiệu năng tốt hơn thì Garbage Collector đang trở thành tính năng “chuẩn” của nhiều ngôn ngữ lập trình mới.

Đối với Java, khi quá trình hoạt động của garbage collector có nguy cơ ảnh hưởng tới performance của ứng dụng, lập trình viên có thể tùy chỉnh garbage collector theo nhiều cách khác nhau để đạt được hiệu năng mong muốn.

4. Làm việc với garbage collector sao cho hiệu quả?

Với các ứng dụng đơn giản, lập trình viên không cần quan tâm nhiều đến garbage collector. Tuy nhiên, nếu họ muốn nâng cao khả năng của bản thân thì việc hiểu cơ chế hoạt động và tùy chỉnh bộ garbage collector là một trong các kỹ năng phải học.

Bên cạnh cơ chế hoạt động của garbage collector, các lập trình viên cần lưu ý một điều, đó là việc thu gom rác ở Java không xác định được và không thể dự đoán garbage collector sẽ chạy ở thời điểm nào. Kể cả khi gọi nó một cách tường minh với System.gc() hay Runtime.gc(), ta vẫn không thể chắc chắn được garbage collector có chạy hay không.

Về việc tùy chỉnh garbage collector, cách tiếp cận tốt nhất là điều chỉnh các setting flag của JVM (chính là các tham số tương ứng với từng bộ garbage collector được liệt kể ở trên). Flag có thể điều chỉnh bộ thu gom rác (ví dụ: Serial, G1, v.v.), quy định kích thước khi cấp phát và kích thước tối đa của vùng nhớ heap mà chương trình sử dụng, hoặc điều chỉnh kích thước của từng nhóm “tuổi”. Ví dụ: bộ garbage collector Parallel có hiệu quả nhưng sẽ gây ra sự cố “stop the world”, làm cho nó phù hợp hơn cho việc xử lý phụ trợ, nơi được chấp nhận tạm dừng để thu gom rác.

Mặt khác, bộ garbage collector CMS được thiết kế để giảm thiểu thời gian tạm dừng, làm cho nó trở nên lý tưởng cho các ứng dụng GUI, nơi đáp ứng quan trọng. Điều chỉnh bổ sung có thể được thực hiện bằng cách thay đổi kích thước heap hoặc các phần của nó và đo hiệu quả thu gom rác bằng cách sử dụng một công cụ như jstat.