लघु जवाब,
कुछ भी करने के बिना, आप 1.5 का एक पहलू से वर्तमान सीमा को धक्का कर सकते हैं। इसका मतलब है कि, यदि आप 800 एमबी की प्रक्रिया करने में सक्षम हैं, तो आप 1200 एमबी की प्रक्रिया कर सकते हैं। इसका मतलब यह भी है कि अगर java -Xm ....
के साथ कुछ चाल से आप उस बिंदु पर जा सकते हैं जहां आपका वर्तमान कोड 7 जीबी संसाधित कर सकता है, तो आपकी समस्या हल हो जाती है, क्योंकि 1.5 कारक आपको 10.5 जीबी तक ले जाएगा, मानते हैं कि आपके पास उस सिस्टम में आपके स्थान पर उपलब्ध है और कि जेवीएम इसे प्राप्त कर सकता है।
लांग जवाब:
त्रुटि सुंदर आत्म वर्णनात्मक है। आपने अपनी कॉन्फ़िगरेशन पर व्यावहारिक स्मृति सीमा को मारा। JVM के साथ आपके पास सीमा के बारे में बहुत सी अटकलें हैं, मुझे इसके बारे में पर्याप्त जानकारी नहीं है, क्योंकि मुझे कोई आधिकारिक जानकारी नहीं मिल रही है। हालांकि, अगर आप किसी भी तरह उपलब्ध स्वैप, कर्नेल पता स्थान उपयोग, मेमोरी विखंडन, आदि जैसे की कमी से सीमित हो जाएगा
क्या अब हो रहा है कि ByteArrayOutputStream
वस्तुओं आकार 32 यदि आप का एक डिफ़ॉल्ट बफर के साथ बनाया जाता है किसी भी आकार की आपूर्ति नहीं (यह आपका मामला है)। जब भी आप ऑब्जेक्ट पर write
विधि को कॉल करते हैं, तो एक आंतरिक मशीनरी शुरू होती है। openjdk implementation release 7u40-b43 जो आपकी त्रुटि के आउटपुट के साथ पूरी तरह मेल खाता है, यह जांचने के लिए कि बफर में बाइट्स लिखने के लिए पर्याप्त जगह है, एक आंतरिक विधि ensureCapacity
का उपयोग करती है। यदि पर्याप्त कमरा नहीं है, तो बफर के आकार को बढ़ाने के लिए एक और आंतरिक विधि grow
कहा जाता है। विधि grow
उचित आकार को परिभाषित करता है और नौकरी करने के लिए Arrays
कक्षा से copyOf
विधि को कॉल करता है। बफर का उचित आकार वर्तमान आकार और सभी सामग्री (वर्तमान सामग्री और नई सामग्री लिखने के लिए) के आकार के बीच अधिकतम है। वर्ग Arrays
(follow the link) से विधि नए बफर के लिए स्थान आवंटित करती है, पुराने बफर की सामग्री को नए पर कॉपी करें और इसे grow
पर वापस कर दें।
आपकी समस्या नए बफर के लिए स्थान के आवंटन पर होती है, कुछ write
के बाद, आप उस बिंदु पर पहुंच जाते हैं जहां उपलब्ध स्मृति समाप्त हो जाती है: java.lang.OutOfMemoryError: Java heap space
।
अगर हम विस्तार में देखें, तो आप 2048 का हिस्सा द्वारा पढ़ रहे हैं तो
- के लिए अपना पहला लिखने 2048
- अपने दूसरे कॉल करने के लिए 32 से बफर के आकार बढ़ता करने के लिए इसे दोगुना होगा 2 * 2048
- आपका तीसरा कॉल इसे 2^2 * 2048 पर ले जाएगा, आपको आवंटन की आवश्यकता से पहले दो बार लिखने का समय है।
- फिर 2^3 * 2048, आपके पास फिर से आवंटित करने से पहले 4 मोर्स लिखने का समय होगा।
- किसी बिंदु पर, आपका बफर आकार 2^18 * 2048 होगा जो 2^1 9 * 1024 या 2^9 * 2^20 (512 एमबी)
- फिर 2^1 9 * 2048 जो 1024 एमबी है या 1 जीबी
कुछ जो आपके वर्णन में अस्पष्ट है वह यह है कि आप 800 एमबी तक पढ़ सकते हैं, लेकिन आगे नहीं जा सकते हैं। आपको मुझे यह समझा देना है।
मुझे उम्मीद है कि आपकी सीमा बिल्कुल 2 की शक्ति होगी (या अगर हम 10 इकाइयों की शक्ति का उपयोग करते हैं तो बंद करें)। उस संबंध में, मैं उम्मीद करता हूं कि आप इनमें से किसी एक के ऊपर तुरंत परेशानी शुरू करें: 256 एमबी, 512 एमबी, 1 जीबी, 2 जीबी, आदि
जब आप उस सीमा को दबाते हैं, तो इसका मतलब यह नहीं है कि आप स्मृति से बाहर हैं, बस इसका मतलब है कि आपके पास पहले से मौजूद बफर के आकार के दो बार बफर आवंटित करना संभव नहीं है। इस अवलोकन को खोलता है अपने काम में सुधार की गुंजाइश: है कि आप का आवंटन और उचित निर्माता
ByteArrayOutputStream bArrStream = new ByteArrayOutputStream(myMaxSize);
यह सिर के ऊपर पृष्ठभूमि स्मृति आवंटन के तहत होता है को कम करने का लाभ दिया है फोन करके यह अग्रिम आरक्षित कर सकते हैं बफर का अधिकतम आकार को खोजने आपको खुश रखने के लिए हुड ऐसा करके, आप अभी 1.5 सीमा तक पहुंचने में सक्षम होंगे। यह बस इसलिए है क्योंकि आखिरी बार बफर बढ़ गया था, यह वर्तमान आकार के आधे से वर्तमान आकार तक चला गया, और किसी बिंदु पर आपके पास मौजूदा बफर और बूढ़े दोनों को याद में मिला। लेकिन अब आप अपनी सीमा के 3 गुना से आगे नहीं जा पाएंगे। स्पष्टीकरण बिल्कुल वही है।
कहा गया है कि, मेरे पास डेटा को दिए गए आकार के हिस्सों, एक समय में एक हिस्से से संसाधित करने के अलावा समस्या को हल करने के लिए कोई जादू सुझाव नहीं है। एक और अच्छा दृष्टिकोण Takahiko Kawasaki के सुझाव का उपयोग करना होगा और MappedByteBuffer
का उपयोग करना होगा। ध्यान रखें कि किसी भी मामले में आपको 10 जीबी की फाइल लोड करने में सक्षम होने के लिए कम से कम 10 जीबी भौतिक मेमोरी या स्वैप मेमोरी की आवश्यकता होगी।
देखें
आपके द्वारा वर्णित नमूना कोड में, आप बस पूरी फ़ाइल को 'ByteArrayOutputStream' में लोड कर रहे हैं। उपयोग का मामला क्या है? वास्तव में पूरे फ़ाइल डेटा को 'बाइट []' में चाहिए? – Santosh
क्या आप मुझे बता सकते हैं कि आप किस जेडीके संस्करण का उपयोग करने की योजना बना रहे हैं, मेरे पास जेडीके 8 और जेडीके 7 या उससे कम के लिए अलग-अलग समाधान हैं। – Bhupi
@Luffy यह जानने के बिना इस प्रश्न का उत्तर देने के लिए समझ में आता है ** क्यों ** इतना डेटा स्मृति में पढ़ा जाता है? – k3b