Trong khi di chuyển từ CMS sang G1 cho một số ứng dụng của chúng tôi, tôi nhận thấy rằng một trong số chúng bị thời gian khởi động kéo dài bởi yếu tố 4. Thời gian dừng ứng dụng do chu trình GC không phải là nguyên nhân. Khi so sánh hành vi của ứng dụng, tôi đã giải tán rằng cái này mang một con số khổng lồ 250 triệu đối tượng trực tiếp sau khi khởi động (trong một đống 12G). Điều tra thêm cho thấy rằng ứng dụng có tốc độ bình thường trong 5 triệu lần phân bổ đầu tiên, nhưng hiệu suất giảm xuống nhiều hơn và nhiều hơn khi các nhóm vật thể sống lớn hơn.Hiệu suất phân bổ có làm giảm đi một số lượng lớn các cá thể trực tiếp khi sử dụng G1 không?
Các thử nghiệm khác cho thấy rằng khi đạt đến một ngưỡng nhất định của các đối tượng trực tiếp, việc phân bổ các đối tượng mới thực sự sẽ chậm lại khi sử dụng G1. Tôi thấy rằng tăng gấp đôi số lượng các đối tượng sống dường như đặt một yếu tố khoảng 2,5 vào thời gian cần thiết cho phân bổ đó. Với các động cơ GC khác, yếu tố chỉ là 2. Điều này thực sự sẽ giải thích sự suy giảm.
Có hai vấn đề mà làm cho tôi nghi ngờ kết luận rằng, mặc dù:
- Ngưỡng khoảng khoảng 5 triệu trường hợp sống dường như có liên quan đến các đống như một toàn thể. Với G1, tôi có thể mong đợi bất kỳ ngưỡng xuống cấp nào như vậy có liên quan đến một khu vực, không phải cho toàn bộ đống.
- Tôi đã xem xét các tài liệu trong web giải thích (hoặc ít nhất là nói rõ) hành vi này, nhưng tôi không tìm thấy. Tôi thậm chí không tìm thấy các khuyến nghị của loại 'Có hơn xxx đối tượng sống là điều ác'.
Vì vậy: sẽ rất tuyệt nếu ai đó có thể cho tôi biết rằng các quan sát của tôi là chính xác và có thể chỉ cho tôi một số tài liệu giải thích hoặc một số đề xuất liên quan đến lĩnh vực này. Hoặc, cách khác, ai đó nói với tôi điều tôi đang làm sai. :)
Đây là một trường hợp thử nghiệm ngắn (chạy nhiều lần, có giá trị trung bình, trừ lần thu gom rác thải hiển thị):
import java.util.HashMap;
/**
* Allocator demonstrates the dependency between number of live objects
* and allocation speed, using various GC algorithms.
* Call it using, e.g.:
* java Allocator -Xmx12g -Xms12g -XX:+PrintGCApplicationStoppedTime -XX:+UseG1GC
* java Allocator -Xmx12g -Xms12g -XX:+PrintGCApplicationStoppedTime
* Deduct stopped times from execution time.
*/
public class Allocator {
public static void main(String[] args) {
timer(2000000, true);
for (int i = 1000000; i <= 32000000; i*=2) {
timer(i, false);
}
for (int i = 32000000; i >= 1000000; i/=2) {
timer(i, false);
}
}
private static void timer(int num, boolean warmup) {
long before = System.currentTimeMillis();
Allocator a = new Allocator();
int size = a.allocate(num);
long after = System.currentTimeMillis();
if (!warmup) {
System.out.println("Time needed for " + num + " allocations: "
+ (after - before) + " millis. Map size = " + size);
}
}
private int allocate(int numElements) {
HashMap<Integer, String> map = new HashMap<>(2*numElements);
for (int i = 0; i < numElements; i++) {
map.put(i, Integer.toString(i));
}
return map.size();
}
}
Nhật ký GC (qua 'PrintGCDetails') và đề cập đến phiên bản java bạn đang sử dụng sẽ hữu ích – the8472
Bản ghi đầy đủ GC của ứng dụng thực tế quá lớn.:) Nhưng dù sao, trường hợp thử nghiệm ở trên thể hiện hành vi. Xin lưu ý rằng vấn đề ở đây là * không * GC tạm dừng. - Tôi sử dụng Java 8 Update 45. Hành vi giống hệt với Windows và Linux. – malamut
câu hỏi là liệu trường hợp kiểm tra của bạn có gây ra các vấn đề tương tự như khối lượng công việc thực tế của bạn hay không. có một hashmap duy nhất giữ cho hàng triệu đối tượng sẽ tạo ra một mảng tham chiếu rất lớn bên trong bản đồ băm, có thể sẽ yêu cầu một vùng cho chính nó, do đó làm cho hầu hết các tham chiếu từ bảng hashmap đến các nút của nó. giữ sách. – the8472