Vâng, có một số câu hỏi trong một ở đây!
1 - Các đối tượng tồn tại trong thời gian ngắn được quản lý như thế nào?
Như đã nói trước đây, JVM hoàn toàn có thể đối phó với một lượng lớn vật thể tồn tại trong thời gian ngắn, vì nó tuân theo Giả thuyết Thế hệ Yếu .
Lưu ý rằng chúng ta đang nói về các đối tượng đã đạt đến bộ nhớ chính (heap). Đây không phải là luôn luôn như vậy. Rất nhiều đối tượng bạn tạo thậm chí không để lại thanh ghi CPU. Ví dụ: hãy xem xét vòng lặp for này
for(int i=0, i<max, i++) {
// stuff that implies i
}
Đừng nghĩ về việc bỏ cuộn vòng lặp (một cách tối ưu mà JVM thực hiện rất nhiều trên mã của bạn). Nếu max
bằng Integer.MAX_VALUE
, vòng lặp của bạn có thể mất một khoảng thời gian để thực thi. Tuy nhiên, i
biến sẽ không bao giờ thoát khỏi khối lặp. Do đó, JVM sẽ đưa biến đó vào thanh ghi CPU, thường xuyên tăng nó lên nhưng sẽ không bao giờ gửi biến trở lại bộ nhớ chính.
Vì vậy, việc tạo ra hàng triệu đối tượng không phải là vấn đề lớn nếu chúng chỉ được sử dụng cục bộ. Họ sẽ chết trước khi được cất giữ trong Eden, vì vậy GC thậm chí sẽ không nhận thấy họ.
2 - Nó có hữu ích để giảm chi phí của GC không?
Như thường lệ, nó phụ thuộc.
Đầu tiên, bạn nên bật tính năng ghi nhật ký GC để có cái nhìn rõ ràng về những gì đang diễn ra. Bạn có thể kích hoạt nó với -Xloggc:gc.log -XX:+PrintGCDetails
.
Nếu ứng dụng của bạn đang dành nhiều thời gian trong chu kỳ GC, thì, vâng, hãy điều chỉnh GC, nếu không, nó có thể không thực sự đáng giá.
Ví dụ: nếu bạn có một GC trẻ cứ sau 100ms mất 10ms, bạn dành 10% thời gian của mình trong GC và bạn có 10 lần thu thập mỗi giây (đó là huuuuuge). Trong trường hợp như vậy, tôi sẽ không dành bất kỳ thời gian nào để điều chỉnh GC, vì 10 GC / s đó sẽ vẫn ở đó.
3 - Một số kinh nghiệm
Tôi đã gặp sự cố tương tự trên một ứng dụng đang tạo ra một lượng lớn lớp nhất định. Trong nhật ký GC, tôi nhận thấy rằng tốc độ tạo của ứng dụng là khoảng 3 GB / s, quá nhiều (cứ đến ... 3 gigabyte dữ liệu mỗi giây ?!).
Vấn đề: Quá nhiều GC thường xuyên gây ra bởi quá nhiều đối tượng được tạo.
Trong trường hợp của tôi, tôi đã đính kèm một trình biên dịch bộ nhớ và nhận thấy rằng một lớp đại diện cho một tỷ lệ phần trăm lớn tất cả các đối tượng của tôi. Tôi đã theo dõi các khởi tạo để phát hiện ra rằng lớp này về cơ bản là một cặp boolean được bao bọc trong một đối tượng. Trong trường hợp đó, có hai giải pháp:
Làm lại thuật toán để tôi không trả về một cặp boolean mà thay vào đó tôi có hai phương thức trả về từng boolean riêng biệt
Lưu vào bộ nhớ cache các đối tượng, biết rằng chỉ có 4 trường hợp khác nhau
Tôi đã chọn cái thứ hai, vì nó ít ảnh hưởng nhất đến ứng dụng và dễ giới thiệu. Tôi đã mất vài phút để đặt một nhà máy với bộ nhớ cache không an toàn cho luồng (tôi không cần an toàn luồng vì cuối cùng tôi chỉ có 4 trường hợp khác nhau).
Tỷ lệ phân bổ giảm xuống 1 GB / s, và tần suất GC trẻ (chia cho 3) cũng vậy.
Hy vọng rằng sẽ giúp!