Tôi đang cố gắng đọc một văn bản lớn văn bản vào bộ nhớ bằng Java. Tại một số điểm nó chạm vào một bức tường và chỉ rác thu thập liên tục. Tôi muốn biết nếu có ai có kinh nghiệm đánh bại GC của Java để gửi với các tập dữ liệu lớn.Hiệu suất kém với danh sách Java lớn
Tôi đang đọc một tệp 8 GB văn bản tiếng Anh, bằng UTF-8, với một câu trong một dòng. Tôi muốn split()
mỗi dòng trên khoảng trắng và lưu trữ các mảng Chuỗi kết quả trong một ArrayList<String[]>
để xử lý thêm. Đây là một chương trình được đơn giản hóa thể hiện sự cố:
/** Load whitespace-delimited tokens from stdin into memory. */
public class LoadTokens {
private static final int INITIAL_SENTENCES = 66000000;
public static void main(String[] args) throws IOException {
List<String[]> sentences = new ArrayList<String[]>(INITIAL_SENTENCES);
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
long numTokens = 0;
String line;
while ((line = stdin.readLine()) != null) {
String[] sentence = line.split("\\s+");
if (sentence.length > 0) {
sentences.add(sentence);
numTokens += sentence.length;
}
}
System.out.println("Read " + sentences.size() + " sentences, " + numTokens + " tokens.");
}
}
Dường như đã cắt và phơi khô phải không? Bạn sẽ nhận thấy tôi thậm chí trước khi kích thước của tôi ArrayList
; Tôi có ít hơn 66 triệu câu và 1,3 tỷ thẻ. Bây giờ nếu bạn whip ra Java object sizes tham chiếu và bút chì của bạn, bạn sẽ thấy rằng nên yêu cầu về:
- 66e6 tài liệu tham khảo
String[]
@ 8 byte ea = 0,5 GB - 66e6
String[]
đối tượng @ 32 byte ea = 2 GB - 66e6
char[]
đối tượng @ 32 byte ea = 2 GB - 1.3e9
String
tài liệu tham khảo @ 8 byte ea = 10 GB - 1.3e9
String
s @ 44 byte ea = 53 GB - 8e9
char
s @ 2 byte ea = 15 GB
83 GB. (Bạn sẽ nhận thấy tôi thực sự cần phải sử dụng kích thước đối tượng 64-bit, vì Compressed OOPs không thể giúp tôi với> 32 GB đống.) Chúng tôi may mắn có một máy RedHat 6 với RAM 128 GB, vì vậy tôi khởi động Máy chủ Java 64 bit của tôi (TM) 64 bit (xây dựng 20.4-b02, chế độ hỗn hợp) từ bộ Java SE 1.6.0_29 của tôi với pv giant-file.txt | java -Xmx96G -Xms96G LoadTokens
chỉ để an toàn và quay lại trong khi tôi xem top
.
Một nơi nào đó ít hơn một nửa thông qua đầu vào, vào khoảng 50-60 GB RSS, bộ thu gom rác song song khởi động lên tới 1300% CPU (hộp 16 proc) và tiến trình đọc dừng. Sau đó, nó đi thêm một vài GB, sau đó tiến trình dừng lại lâu hơn nữa. Nó lấp đầy 96 GB và chưa hoàn thành. Tôi đã để cho nó đi trong một giờ rưỡi, và nó chỉ cháy ~ 90% thời gian hệ thống làm GC. Điều đó có vẻ cực đoan.
Để đảm bảo rằng tôi không bị điên, tôi đã đánh lừa Python tương đương (tất cả hai dòng;) và nó chạy để hoàn thành trong khoảng 12 phút và 70 GB RSS.
Vì vậy: tôi đang làm điều gì đó ngu ngốc? (Ngoài những thứ không hiệu quả, mọi thứ đang được lưu trữ, mà tôi thực sự không thể giúp - và thậm chí nếu cấu trúc dữ liệu của tôi có chất béo, miễn là chúng phù hợp, Java không nên chỉ nghẹt thở.) GC tư vấn cho đống thực sự lớn? Tôi đã thử -XX:+UseParNewGC
và có vẻ như còn tồi tệ hơn.
Đối tượng 'char []' sao lưu các chuỗi? –
Trong các đối tượng 'String': tiêu đề đối tượng 24 byte + 8 byte' char [] 'con trỏ + bắt đầu 4 byte, bù đắp và hashcode, nếu tính toán của tôi là chính xác. –
Đó là tham chiếu 'char []' * * - nhưng về bản thân 'char []' * thì sao? Một mảng 'char []' có một đối tượng trên không ... –