यह जावा के साथ लंबे समय से शिकायत की गई है, लेकिन यह काफी हद तक अर्थहीन है, और आमतौर पर गलत जानकारी को देखने पर आधारित है। कुछ सामान्य वाक्यांश कुछ इस तरह हैं "जावा पर हैलो वर्ल्ड 10 मेगाबाइट लेता है! इसकी आवश्यकता क्यों है?" खैर, यहां 64-बिट JVM पर 4 गीगाबाइट लेने का दावा करके हैलो वर्ल्ड बनाने का एक तरीका है ... कम से कम एक प्रकार का माप।
java -Xms1024m -Xmx4096m com.example.Hello
मेमोरी को मापने के विभिन्न तरीके
लिनक्स पर, शीर्ष कमांड आपको मेमोरी के लिए कई अलग-अलग नंबर देता है। यह हैलो वर्ल्ड उदाहरण के बारे में क्या कहता है:
PID USER PR NI VIRT RES SHR S% CPU% MEM TIME + COMMAND
2120 किग्रागरी 20 0 4373 मी 15 मी 7152 एस 0 0.2 0: 00.10 जावा
- VIRT वर्चुअल मेमोरी स्पेस है: वर्चुअल मेमोरी मैप में सब कुछ का योग (नीचे देखें)। यह काफी हद तक व्यर्थ है, सिवाय इसके कि यह (नीचे देखें) नहीं है।
- आरईएस निवासी सेट आकार है: उन पृष्ठों की संख्या जो वर्तमान में रैम में निवासी हैं। लगभग सभी मामलों में, यह एकमात्र संख्या है जिसे आपको "बहुत बड़ा" कहते समय उपयोग करना चाहिए। लेकिन यह अभी भी बहुत अच्छी संख्या नहीं है, खासकर जब जावा के बारे में बात कर रहे हैं।
- SHR निवासी मेमोरी की मात्रा है जो अन्य प्रक्रियाओं के साथ साझा की जाती है। एक जावा प्रक्रिया के लिए, यह आम तौर पर साझा पुस्तकालयों और मेमोरी-मैप किए गए JARfiles तक सीमित है। इस उदाहरण में, मेरे पास केवल एक जावा प्रक्रिया चल रही थी, इसलिए मुझे संदेह है कि 7k ओएस द्वारा उपयोग किए जाने वाले पुस्तकालयों का एक परिणाम है।
- डिफ़ॉल्ट रूप से SWAP चालू नहीं है, और यहां नहीं दिखाया गया है। यह वर्चुअल मेमोरी की मात्रा को इंगित करता है जो वर्तमान में डिस्क पर निवासी है, चाहे वह वास्तव में स्वैप स्पेस में हो या नहीं । ओएस रैम में सक्रिय पेज रखने के बारे में बहुत अच्छा है, और स्वैपिंग के लिए एकमात्र इलाज है (1) अधिक मेमोरी खरीदें, या (2) प्रक्रियाओं की संख्या कम करें, इसलिए इस संख्या को अनदेखा करना सबसे अच्छा है।
विंडोज टास्क मैनेजर के लिए स्थिति थोड़ी अधिक जटिल है। विंडोज एक्सपी के तहत, "मेमोरी यूसेज" और "वर्चुअल मेमोरी साइज" कॉलम हैं, लेकिन आधिकारिक दस्तावेज़ीकरण का मतलब क्या है, इस पर चुप है। विंडोज विस्टा और विंडोज 7 अधिक कॉलम जोड़ते हैं, और वे वास्तव में प्रलेखित हैं । इनमें से, "वर्किंग सेट" माप सबसे उपयोगी है; यह लगभग लिनक्स पर RES और SHR के योग से मेल खाता है।
वर्चुअल मेमोरी मैप को समझना
एक प्रक्रिया द्वारा उपभोग की जाने वाली आभासी मेमोरी सब कुछ है जो प्रक्रिया मेमोरी मैप में है। इसमें डेटा (उदाहरण के लिए, जावा हीप), लेकिन प्रोग्राम द्वारा उपयोग की जाने वाली सभी साझा लाइब्रेरी और मेमोरी-मैप की गई फ़ाइलें भी शामिल हैं। लिनक्स पर, आप प्रक्रिया स्थान में मैप की गई सभी चीजों को देखने के लिए pmap कमांड का उपयोग कर सकते हैं (यहां से मैं केवल लिनक्स का उल्लेख करने जा रहा हूं, क्योंकि यह वही है जो मैं उपयोग करता हूं; मुझे यकीन है कि इसके लिए समान उपकरण हैं खिड़कियाँ)। यहां "हैलो वर्ल्ड" प्रोग्राम के मेमोरी मैप का एक अंश दिया गया है; संपूर्ण मेमोरी मैप 100 लाइनों से अधिक लंबा है, और एक हजार-लाइन सूची होना असामान्य नहीं है।
0000000040000000 36K rx--/usr/local/java/jdk-1.6-x64/bin/wava
0000000040108000 8K rwx-- /usr/local/java/jdk-1.6-x64/bin/java
0000000040eba000 676K rwx-- [anon]
00000006fae00000 21248K rwx-- [anon]
00000006fc2c0000 62720K rwx-- [एनोन]
0000000700000000 699072K rwx-- [एनोन]
000000072aab0000 2097152K rwx-- [anon]
00000007aaab0000 349504K rwx-- [एनोन]
00000007c0000000 1048576K rwx-- [आन]
...
00007fa1ed00d000 1652K r-xs- /us/local/java/jdk-1.6-x64/jre/lib/rt.jar
...
00007fa1ed1d3000 1024K rwx-- [एनोन]
00007fa1ed2d3000 4K ----- [एनोन]
00007fa1ed2d4000 1024K rwx-- [एनोन]
00007fa1ed3d4000 4K ----- [एनोन]
...
00007fa1f20d3000 164K rx--/usr/local/java/jdk-1.6-x64/jre/lib/amd64/libjava.so
00007fa1f20fc000 1020K ----- /rr/local/java/jdk-1.6-x64/jre/lib/amd64/libjava.so
00007fa1f21fb000 28K rwx-- /usr/local/java/jdk-1.6-x64/jre/lib/amd64/libjava.so
...
00007fa1f34aa000 1576K rx-- /lib/x86_64-linux-gnu/libc-2.13.so
00007fa1f3634000 2044K ----- /lib/x86_64-linux-gnu/libc-2.13.so
00007fa1f3833000 16K rx-- /lib/x86_64-linux-gnu/libc-2.13.so
00007fa1f3837000 4K rwx-- /lib/x86_64-linux-gnu/libc-2.13.so
...
प्रारूप की एक त्वरित व्याख्या: प्रत्येक पंक्ति खंड के वर्चुअल मेमोरी पते से शुरू होती है। इसके बाद खंड आकार, अनुमतियाँ और खंड का स्रोत है। यह अंतिम आइटम या तो एक फ़ाइल या "एनॉन" है, जो मिमीप के माध्यम से आवंटित मेमोरी के एक ब्लॉक को इंगित करता है ।
ऊपर से शुरू, हमारे पास है
- जेवीएम लोडर (यानी, जब आप टाइप करते हैं तो प्रोग्राम चलता है
java
)। यह बहुत छोटा है; यह सब कुछ साझा पुस्तकालयों में लोड होता है जहां वास्तविक JVM कोड संग्रहीत होता है।
- जावा ढेर और आंतरिक डेटा को धारण करने वाले एनॉन ब्लॉकों का एक गुच्छा। यह एक सूर्य जेवीएम है, इसलिए ढेर कई पीढ़ियों में टूट गया है, जिनमें से प्रत्येक का अपना मेमोरी ब्लॉक है। ध्यान दें कि जेवीएम
-Xmx
मूल्य के आधार पर वर्चुअल मेमोरी स्पेस आवंटित करता है ; यह इसे एक सन्निहित ढेर के लिए अनुमति देता है। -Xms
मूल्य कहने के लिए ढेर के कितना है "उपयोग में" जब कार्यक्रम शुरू होता है, और ट्रिगर कचरा संग्रहण के रूप में उस सीमा से संपर्क किया गया है आंतरिक रूप से प्रयोग किया जाता है।
- एक मेमोरी-मैपेड JARfile, इस मामले में "JDK क्लासेस" रखने वाली फ़ाइल। जब आप JAR को मेमोरी-मैप करते हैं, तो आप इसके भीतर मौजूद फाइलों को बहुत कुशलता से एक्सेस कर सकते हैं (प्रत्येक बार शुरू से इसे पढ़ते हुए)। सूर्य JVM क्लासपाथ पर सभी JAR को मेमोरी-मैप करेगा; यदि आपके एप्लिकेशन कोड को JAR तक पहुंचने की आवश्यकता है, तो आप इसे मेमोरी-मैप भी कर सकते हैं।
- प्रति-थ्रेड डेटा दो थ्रेड्स के लिए। 1M ब्लॉक थ्रेड स्टैक है। मेरे पास 4k ब्लॉक के लिए एक अच्छी व्याख्या नहीं थी, लेकिन @ericsoe ने इसे "गार्ड ब्लॉक" के रूप में पहचाना: इसमें अनुमतियाँ पढ़ने / लिखने की ज़रूरत नहीं है, इसलिए एक्सेस किए जाने पर सेगमेंट में खराबी आएगी, और JVM इसे पकड़ता है और अनुवाद करता है यह करने के लिए एक
StackOverFlowError
। एक वास्तविक ऐप के लिए, आप दर्जनों देखेंगे कि स्मृति मानचित्र के माध्यम से दोहराए गए इन प्रविष्टियों में से सैकड़ों नहीं।
- साझा पुस्तकालयों में से एक जो वास्तविक जेवीएम कोड रखता है। इनमें से कई हैं।
- सी मानक पुस्तकालय के लिए साझा पुस्तकालय। यह सिर्फ कई चीजों में से एक है जो जेवीएम लोड करता है जो कि जावा का कड़ाई से हिस्सा नहीं है।
साझा लाइब्रेरी विशेष रूप से दिलचस्प हैं: प्रत्येक साझा लाइब्रेरी में कम से कम दो खंड होते हैं: लाइब्रेरी कोड वाला एक रीड-ओनली सेगमेंट, और एक रीड-राइट सेगमेंट जिसमें लाइब्रेरी के लिए वैश्विक प्रति-प्रक्रिया डेटा होता है (मुझे नहीं पता कि क्या है बिना अनुमति वाला सेगमेंट है; मैंने इसे केवल x64 लिनक्स पर देखा है)। पुस्तकालय का केवल-पढ़ने का हिस्सा उन सभी प्रक्रियाओं के बीच साझा किया जा सकता है जो पुस्तकालय का उपयोग करते हैं; उदाहरण के लिए, libc
1.5M वर्चुअल मेमोरी स्पेस है जिसे साझा किया जा सकता है।
वर्चुअल मेमोरी साइज कब महत्वपूर्ण है?
वर्चुअल मेमोरी मैप में बहुत सारा सामान होता है। इसमें से कुछ केवल पढ़ने के लिए है, कुछ इसे साझा किया गया है, और कुछ इसे आवंटित किया गया है लेकिन कभी भी छुआ नहीं गया है (उदाहरण के लिए, इस उदाहरण में लगभग सभी 4 जी के ढेर)। लेकिन ऑपरेटिंग सिस्टम केवल उसे लोड करने के लिए पर्याप्त स्मार्ट है, इसलिए वर्चुअल मेमोरी का आकार काफी हद तक अप्रासंगिक है।
जहाँ वर्चुअल मेमोरी का आकार महत्वपूर्ण है, यदि आप 32-बिट ऑपरेटिंग सिस्टम पर चल रहे हैं, जहाँ आप केवल 2Gb (या, कुछ मामलों में, 3Gb) को प्रोसेस एड्रेस स्पेस आवंटित कर सकते हैं। उस स्थिति में आप एक दुर्लभ संसाधन के साथ काम कर रहे हैं, और एक बड़े फ़ाइल को मेमोरी-मैप करने या बहुत सारे थ्रेड बनाने के लिए अपने ढेर के आकार को कम करने जैसे ट्रेडऑफ़ बनाने पड़ सकते हैं।
लेकिन, यह देखते हुए कि 64-बिट मशीनें सर्वव्यापी हैं, मुझे नहीं लगता कि वर्चुअल मेमोरी साइज़ पूरी तरह अप्रासंगिक आँकड़ा होने से बहुत पहले होगा।
रेजिडेंट सेट का आकार कब महत्वपूर्ण है?
रेजिडेंट सेट का आकार वर्चुअल मेमोरी स्पेस का वह हिस्सा है जो वास्तव में रैम में होता है। यदि आपका RSS आपकी कुल भौतिक मेमोरी का एक महत्वपूर्ण हिस्सा है, तो चिंता शुरू करने का समय आ सकता है। यदि आपका RSS आपकी सभी भौतिक मेमोरी को बढ़ाता है, और आपका सिस्टम स्वैप करना शुरू कर देता है, तो चिंता करना शुरू करने का अच्छा समय है।
लेकिन आरएसएस भी गुमराह कर रहा है, विशेष रूप से एक हल्की भरी हुई मशीन पर। ऑपरेटिंग सिस्टम एक प्रक्रिया द्वारा उपयोग किए गए पृष्ठों को पुनः प्राप्त करने के लिए बहुत प्रयास नहीं करता है। ऐसा करने से बहुत कम लाभ मिलता है, और यदि प्रक्रिया भविष्य में पृष्ठ को छूती है, तो एक महंगे पृष्ठ दोष की संभावना है। परिणामस्वरूप, RSS आँकड़ा में बहुत सारे पृष्ठ शामिल हो सकते हैं जो सक्रिय उपयोग में नहीं हैं।
जमीनी स्तर
जब तक आप स्वैप नहीं कर रहे हैं, तब तक इस बारे में चिंतित न हों कि विभिन्न मेमोरी आंकड़े आपको क्या बता रहे हैं। इस चेतावनी के साथ कि एक निरंतर बढ़ता आरएसएस किसी तरह की स्मृति रिसाव का संकेत दे सकता है।
जावा प्रोग्राम के साथ, ढेर में क्या हो रहा है, इस पर ध्यान देना कहीं अधिक महत्वपूर्ण है। भस्म किए गए स्थान की कुल मात्रा महत्वपूर्ण है, और कुछ कदम हैं जिन्हें आप कम कर सकते हैं। अधिक महत्वपूर्ण वह समय है जो आप कचरा संग्रह में खर्च करते हैं, और ढेर के किन हिस्सों को एकत्र किया जा रहा है।
डिस्क (यानी, एक डेटाबेस) तक पहुंचना महंगा है, और मेमोरी सस्ती है। यदि आप एक दूसरे के लिए व्यापार कर सकते हैं, तो ऐसा करें।