क्या लिनक्स मुझसे पूछे बिना मेरी प्रक्रियाओं को मारना शुरू कर देगा कि क्या मेमोरी कम हो गई है?


66

मैं कई मेमोरी-इंटेंसिव प्रोग्राम (2-5 जीबी) बैक-टू-बैक चलाने के लिए कमांड के साथ एक शेल स्क्रिप्ट चला रहा था। जब मैं अपनी स्क्रिप्ट की प्रगति पर जाँच करने के लिए वापस गया तो मुझे यह जानकर आश्चर्य हुआ कि मेरी कुछ प्रक्रियाएँ थीं Killed, जैसा कि मेरे टर्मिनल ने मुझे बताया था। बाद में Killedशुरू किए गए कार्यक्रमों से पहले कई कार्यक्रम क्रमिक रूप से पूरे हो चुके थे , लेकिन बाद में सभी कार्यक्रम एक विभाजन दोष में विफल रहे (जो मेरे कोड में बग के कारण हो सकता है या नहीं हो सकता है, पढ़ते रहें)।

मैंने अपने द्वारा उपयोग किए जा रहे विशेष क्लस्टर के उपयोग के इतिहास को देखा और देखा कि किसी ने एक ही समय में कई मेमोरी-गहन प्रक्रियाएं शुरू कर दी हैं और ऐसा करने में क्लस्टर के लिए उपलब्ध वास्तविक मेमोरी (और संभवतः यहां तक ​​कि स्वैप स्थान) को समाप्त कर दिया है। जब तक मैं समझ सकता हूं, ये मेमोरी-इंटेंसिव प्रक्रियाएं उसी समय चलने लगीं, जब मुझे अपने कार्यक्रमों में समस्या होने लगी।

क्या यह संभव है कि एक बार जब यह मेमोरी से बाहर चलने लगे तो लिनक्स ने मेरे प्रोग्राम्स को मार दिया? और क्या यह संभव है कि बाद में मुझे जो विभाजन दोष मिले, वे मेरे कार्यक्रमों को चलाने के लिए उपलब्ध स्मृति की कमी के कारण थे (मेरे कोड में बग के बजाय)?


2
जब आप मेमोरी आवंटित करते हैं, तो क्या आपके पास यह जांचने के लिए एक स्टेटमेंट है कि क्या मेमोरी सफलतापूर्वक आवंटित की गई थी? यह एक सुराग प्रदान करना चाहिए कि क्या आपके कोड में बग है या क्या यह सिस्टम में मेमोरी की कमी के कारण था।
अप्रयुक्त जू

जवाबों:


72

यह।

लिनक्स में दो अलग-अलग मेमोरी स्थितियां हो सकती हैं। आपका सामना किसके मूल्य पर निर्भर करता है sysctl vm.overcommit_memory( /proc/sys/vm/overcommit_memory)

परिचय:
कर्नेल वह कार्य कर सकता है जिसे 'मेमोरी ओवरकमिट' कहा जाता है। यह तब है जब कर्नेल प्रोग्राम को अधिक मेमोरी आवंटित करता है जो वास्तव में सिस्टम में मौजूद है। यह इस उम्मीद में किया जाता है कि कार्यक्रम वास्तव में आवंटित की गई सभी मेमोरी का उपयोग नहीं करेंगे, क्योंकि यह काफी सामान्य घटना है।

overcommit_memory = 2

जब overcommit_memoryसेट किया जाता है 2, तो कर्नेल किसी भी ओवरकम का प्रदर्शन नहीं करता है। इसके बजाय जब किसी प्रोग्राम को मेमोरी आवंटित की जाती है, तो उस मेमोरी को एक्सेस करने की गारंटी दी जाती है। यदि सिस्टम के पास आवंटन अनुरोध को पूरा करने के लिए पर्याप्त खाली मेमोरी नहीं है, तो कर्नेल अनुरोध के लिए असफलता लौटाएगा। यह स्थिति को इनायत करने के लिए कार्यक्रम पर निर्भर है। यदि यह जांच नहीं करता है कि आवंटन सफल हुआ जब यह वास्तव में विफल हो गया, तो आवेदन अक्सर एक segfault का सामना करेगा।

सेगफॉल्ट के मामले में, आपको इस तरह की आउटपुट में एक लाइन मिलनी चाहिए dmesg:

[1962.987529] myapp[3303]: segfault at 0 ip 00400559 sp 5bc7b1b0 error 6 in myapp[400000+1000]

इसका at 0मतलब है कि एप्लिकेशन ने एक अनइंस्टॉल किए गए पॉइंटर को एक्सेस करने की कोशिश की, जो असफल मेमोरी आवंटन कॉल का परिणाम हो सकता है (लेकिन यह एकमात्र तरीका नहीं है)।

overcommit_memory = 0 और 1

जब overcommit_memoryकरने के लिए सेट कर दिया जाता 0या 1, ओवरकमिट सक्षम किया गया है, और कार्यक्रमों अधिक स्मृति की तुलना में वास्तव में उपलब्ध है आवंटित करने के लिए अनुमति दी जाती है।

हालाँकि, जब कोई प्रोग्राम उस मेमोरी का उपयोग करना चाहता है जिसे वह आवंटित किया गया था, लेकिन कर्नेल पाता है कि वास्तव में उसे संतुष्ट करने के लिए पर्याप्त मेमोरी नहीं है, इसे कुछ मेमोरी वापस पाने की आवश्यकता है। यह पहले विभिन्न मेमोरी क्लीनअप कार्य करने की कोशिश करता है, जैसे कि फ्लशिंग कैश, लेकिन यदि यह पर्याप्त नहीं है तो यह एक प्रक्रिया को समाप्त कर देगा। यह समाप्ति OOM-Killer द्वारा की जाती है। OOM-Killer सिस्टम को यह देखने के लिए देखता है कि कौन से प्रोग्राम किस मेमोरी का उपयोग कर रहे हैं, वे कितने समय से चल रहे हैं, कौन उन्हें चला रहा है, और कई अन्य कारक जो यह निर्धारित करते हैं कि कौन मारा जाता है।

इस प्रक्रिया के मारे जाने के बाद, इसका उपयोग करने वाली मेमोरी को मुक्त कर दिया गया है, और जो प्रोग्राम सिर्फ आउट-ऑफ-मेमोरी स्थिति का कारण बनता है, उसकी स्मृति की आवश्यकता है।

हालांकि, इस मोड में भी, कार्यक्रमों को अभी भी आवंटन अनुरोधों से इनकार किया जा सकता है। जब overcommit_memoryयह है 0, कर्नेल एक सर्वश्रेष्ठ अनुमान लेने की कोशिश करता है जब उसे आवंटन अनुरोधों को अस्वीकार करना शुरू करना चाहिए। जब इसे सेट किया जाता है 1, तो मुझे यकीन नहीं है कि यह निर्धारित करने के लिए क्या निर्धारण का उपयोग करता है जब इसे किसी अनुरोध से इनकार करना चाहिए लेकिन यह बहुत बड़े अनुरोधों से इनकार कर सकता है।

आप देख सकते हैं कि क्या OOM-Killer के उत्पादन को देखने dmesgऔर एक संदेश खोजने के लिए शामिल है:

[11686.043641] Out of memory: Kill process 2603 (flasherav) score 761 or sacrifice child
[11686.043647] Killed process 2603 (flasherav) total-vm:1498536kB, anon-rss:721784kB, file-rss:4228kB

इसलिए, ऐसा लगता है कि दोनों स्थितियां मेरे साथ हुईं।
न्यूट्रॉनस्टार

@ जोशुआ मैंने अभी जवाब अपडेट किया है। मैं उल्लेख करना भूल गया कि आप अभी भी overcommit_memory0 या 2 पर सेट होने पर आवंटन विफलता प्राप्त कर सकते हैं
पैट्रिक

मुझे लगता है कि पोस्ट में OOM हत्यारे को टैम करने के लिए एक लिंक संपादित करना सार्थक हो सकता है।
0xC0000022L

@ 0xC0000022L धन्यवाद, यह एक अच्छा लेख है (हालांकि थोड़ा पुराना है)। मैं OOM हत्यारे को नियंत्रित करने के बारे में कुछ भी नहीं कहना चाहता था क्योंकि यह सवाल का हिस्सा नहीं है (और यह एक छोटा विषय नहीं है), और हमारे पास यहाँ अन्य सवालों का एक टन है।
पैट्रिक

1
@ माइकर्स का कहना है कि ओओएम किलर के व्यवहार का इस पर नियंत्रण करने से कोई लेना-देना नहीं है। सवाल यह था कि क्या लिनक्स अपने कार्यक्रमों को मार देगा। लिनक्स को ऐसा करने से कैसे रोका जाए, पहले यह स्थापित करने की आवश्यकता है कि यह वास्तव में लिनक्स कर रहा है। और अगर overcommit_memory=2, OOM किलर भी सक्षम नहीं है, तो इसे नियंत्रित करना अप्रासंगिक है। हालाँकि एक बार जब हम यह स्थापित कर लेते हैं कि यह OOM किलर है, तो यह एक अन्य विषय बन जाता है, जिसमें यहाँ कई अन्य प्रश्न और उत्तर होते हैं।
पैट्रिक

16

सच्चाई यह है कि आप इस पर ध्यान दिए बिना कि किस तरीके से देखते हैं - क्या आपकी प्रक्रिया सिस्टम के मेमोरी मैनेजर के कारण या किसी और चीज के कारण चोक हो गई है - यह अभी भी एक बग है। उस सभी डेटा का क्या हुआ जो आप मेमोरी में प्रोसेस कर रहे थे? इसे बचाना चाहिए था।

जबकि overcommit_memory=लिनक्स OOM प्रबंधन को विन्यस्त का सबसे सामान्य तरीका है, यह भी तरह की प्रक्रिया प्रति समायोजित किया जा सकता:

echo [-+][n] >/proc/$pid/oom_adj

-17उपरोक्त में उपयोग करने से एक प्रक्रिया को आउट-ऑफ-मेमोरी प्रबंधन से बाहर रखा जाएगा। शायद आम तौर पर एक महान विचार नहीं है, लेकिन अगर आप बग-शिकार कर रहे हैं तो यह सार्थक हो सकता है - खासकर यदि आप यह जानना चाहते हैं कि यह ओओएम था या आपका कोड। संख्या को सकारात्मक रूप से बढ़ाने से ओओएम घटना में प्रक्रिया के मारे जाने की संभावना अधिक हो जाएगी, जो आपको कम-मेमोरी स्थितियों में अपने कोड के लचीलेपन को बेहतर ढंग से किनारे करने और आवश्यक होने पर आपको शान से बाहर निकलने के लिए सक्षम कर सकती है।

आप प्रति प्रक्रिया OOM हैंडलर की वर्तमान सेटिंग्स की जाँच कर सकते हैं जैसे:

cat /proc/$pid/oom_score 

और आप आत्महत्या कर सकते हैं:

sysctl vm.panic_on_oom=1
sysctl kernel.panic=X

यह कंप्यूटर को आउट-ऑफ-मेमोरी स्थिति की स्थिति में रिबूट करने के लिए सेट करेगा। यदि आप Xकंप्यूटर को रिबूट करने से पहले एक कर्नेल घबराहट के बाद रुकने की इच्छा रखते हैं, तो आप सेकंड के ऊपर सेट करें । जंगली बनो।

और अगर, किसी कारण से, आप इसे पसंद करते हैं, तो इसे लगातार बनाए रखें:

echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf

यह एक साझा क्लस्टर है जिसका मैं उपयोग कर रहा हूं, मुझे यकीन है कि अन्य उपयोगकर्ता इसकी सहमति के बिना इसे पुनः आरंभ करने की सराहना नहीं करेंगे।
न्यूट्रॉनस्टार

3
@ जोशुआ - मुझे बहुत गंभीरता से संदेह है कि कोई भी इसे पसंद करेगा - यह असिमोव के रोबोटिक्स के नियमों को भी गलत ठहराता है। दूसरी ओर, जैसा कि मैंने उल्लेख किया है, आप OOM प्रति प्रक्रिया को दूसरे तरीके से भी कॉन्फ़िगर कर सकते हैं। यह कहना है कि आप व्यक्तिगत रूप से प्रक्रिया के अनुसार अपने स्वयं के परिभाषित नियमों के आधार पर ट्राइएज कर सकते हैं। इस तरह की बात से लगता है कि यह साझा क्लस्टर परिदृश्य में विशेष रूप से उपयोगी हो सकता है।
चाटुकार
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.