मैं जावा के साथ मेमोरी में एक बड़ा टेक्स्ट कॉर्पस पढ़ने की कोशिश कर रहा हूं। किसी बिंदु पर यह एक दीवार हिट करता है और केवल कचरा अंततः इकट्ठा होता है। मैं जानना चाहता हूं कि किसी को भी बड़े डेटा सेट के साथ प्रस्तुत करने के लिए जावा के जीसी को मारने का अनुभव है।बड़ी जावा सूचियों के साथ खराब प्रदर्शन
मैं यूटीएफ -8 में, एक वाक्य के साथ एक वाक्य के साथ, अंग्रेजी पाठ की 8 जीबी फ़ाइल पढ़ रहा हूं। मैं split()
व्हाइटस्पेस पर प्रत्येक पंक्ति चाहता हूं और परिणामस्वरूप स्ट्रिंग एरे को ArrayList<String[]>
में आगे प्रोसेसिंग के लिए स्टोर करना चाहता हूं। यहां एक सरल प्रोग्राम है जो समस्या को प्रदर्शित करता है:
/** 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.");
}
}
सुंदर कट-एंड-सूखे लगता है, है ना? आप देखेंगे कि मैं अपने ArrayList
का आकार भी चुकाता हूं; मेरे पास 66 मिलियन से कम वाक्यों और 1.3 बिलियन टोकन हैं। अब अगर आप अपने Java object sizes संदर्भ और अपने पेंसिल बाहर कोड़ा, तो आप उस के बारे में की आवश्यकता होती है चाहिए मिल जाएगा:
- 66e6
String[]
संदर्भ @ 8 बाइट्स ईए = 0.5 जीबी - 66e6
String[]
वस्तुओं @ 32 बाइट्स ईए = 2 जीबी - 66e6
char[]
वस्तुओं @ 32 बाइट्स ईए = 2 जीबी - 1.3e9
String
संदर्भ @ 8 बाइट्स ईए = 10 जीबी - 1.3e9
String
रों @ 44 बाइट्स ईए = 53 जीबी +०१२३५१६४१०
- 8e9
char
रों @ 2 बाइट्स ईए = 15 जीबी
83 जीबी। (आपको पता चलेगा कि मुझे वास्तव में 64-बिट ऑब्जेक्ट आकारों का उपयोग करने की आवश्यकता है, क्योंकि Compressed OOPs मुझे 32 जीबी ढेर के साथ मदद नहीं कर सकता है।) हम भाग्यशाली हैं कि 128 जीबी रैम के साथ रेडहाट 6 मशीन है, इसलिए मैं आग लगाना मेरे जावा हॉटस्पॉट (टीएम) 64-बिट सर्वर वीएम (20.4-बी 022, मिश्रित मोड का निर्माण) मेरे जावा एसई 1.6.0_2 9 किट से pv giant-file.txt | java -Xmx96G -Xms96G LoadTokens
के साथ बस सुरक्षित होने के लिए, और top
देखते समय वापस लातें।
इनपुट के माध्यम से कहीं भी कम से कम 50-60 जीबी आरएसएस पर, समांतर कचरा कलेक्टर 1300% सीपीयू (16 प्रोसेस बॉक्स) तक पहुंच जाता है और प्रगति स्टॉप पढ़ता है। फिर यह कुछ और जीबी चला जाता है, फिर प्रगति भी लंबे समय तक रुक जाती है। यह 96 जीबी भरता है और अभी तक नहीं किया गया है। मैंने इसे डेढ़ घंटे तक जाने दिया है, और यह सिर्फ जीसी कर रहे ~ 90% सिस्टम समय जल रहा है। यह चरम लगता है।
यह सुनिश्चित करने के लिए कि मैं पागल नहीं था, मैंने समकक्ष पायथन (सभी दो पंक्तियों) को मार दिया और यह लगभग 12 मिनट और 70 जीबी आरएसएस में पूरा होने के लिए भाग गया।
तो: क्या मैं कुछ गूंगा कर रहा हूं? (आम तौर पर अक्षम तरीके से चीजों को संग्रहीत किया जा रहा है, जो मैं वास्तव में मदद नहीं कर सकता - और यहां तक कि यदि मेरी डेटा संरचनाएं वसा होती हैं, तब तक जब तक वे फिट होते हैं, जावा को को सख्त नहीं करना चाहिए।) क्या जादू है वास्तव में बड़े ढेर के लिए जीसी सलाह? मैंने -XX:+UseParNewGC
को आजमाया और यह और भी बदतर लगता है।
तारों का समर्थन करने वाले 'char []' ऑब्जेक्ट कहां हैं? –
'स्ट्रिंग' ऑब्जेक्ट्स में: 24 बाइट ऑब्जेक्ट हेडर + 8 बाइट 'char []' पॉइंटर + 4 बाइट स्टार्ट, ऑफसेट और हैशकोड, अगर मेरी गणना सही है। –
यह 'char [] '* संदर्भ * है - लेकिन' char []' * ऑब्जेक्ट्स * के बारे में क्या है? एक 'char [] 'सरणी में ऑब्जेक्ट ओवरहेड भी है ... –