प्रतिनिधि इंटरव्यू विषय

लिनक्स साक्षात्कार: मेमोरी मुक्त होने के बाद भी RSS अधिक क्यों बना रहता है?

सामान्यकठिन
Offer.cc संपादकीय टीमप्रकाशित अपडेट किया गया

प्रश्न

glibc malloc का उपयोग करने वाली एक 64-थ्रेड लिनक्स सेवा एक बैच के दौरान 800 MiB से 6 GiB RSS तक बढ़ जाती है। बैच के बीस मिनट बाद, लाइव एलोकेशन्स वापस 1.1 GiB पर आ जाते हैं लेकिन 8 GiB cgroup सीमा के तहत RSS 5.2 GiB पर बना रहता है। ऐसा क्यों हो सकता है, आप एलोकेटर रिटेंशन या फ्रैग्मेंटेशन से लीक को कैसे अलग करेंगे, और 120 ms p99 लेटेंसी SLO का उल्लंघन किए बिना इसका समाधान कैसे करेंगे?

प्रॉम्प्ट और लागू होने वाला परिदृश्य

glibc malloc का उपयोग करने वाली एक 64-थ्रेड लिनक्स सेवा 800 MiB RSS पर शुरू होती है। एक आवधिक (पीरियोडिक) बैच RSS को 6 GiB तक ले जाता है। बैच समाप्त होने के बीस मिनट बाद, एप्लिकेशन का हीप प्रोफाइलर 1.1 GiB लाइव एलोकेशन्स की रिपोर्ट करता है, लेकिन RSS 5.2 GiB पर बना रहता है। यह प्रोसेस 8 GiB cgroup सीमा के तहत चलती है और इसका 120 ms p99 लेटेंसी SLO है। बताएं कि free() यह गारंटी क्यों नहीं देता कि RSS कम होगा, यह सिद्ध करें कि क्या यह अंतर एक लीक है, एलोकेटर रिटेंशन है, फ्रैग्मेंटेशन है, या कोई अन्य मैपिंग है, और एक सुरक्षित समाधान चुनें।

थ्रेड काउंट, मेमोरी मान, निष्क्रिय (आइडल) अंतराल, सीमा और SLO अभ्यास की मान्यताएं (एजम्प्शन्स) हैं। एक नेटिव प्रोसेस, glibc malloc, cgroup v2, कोई चाइल्ड प्रोसेस नहीं, और एक दोहराने योग्य बैच मान लें। एक प्रबंधित रनटाइम (मैनेज्ड रनटाइम) अपना स्वयं का हीप, गारबेज कलेक्टर और नेटिव-एलोकेशन लेयर्स जोड़ेगा। यह प्रश्न general से संबंधित है क्योंकि मुख्य कौशल लिनक्स प्रोसेस अकाउंटिंग और एलोकेटर व्यवहार है, न कि एप्लिकेशन-भाषा सिंटैक्स।

वर्तमान साक्षात्कार सामग्री स्पष्ट रूप से फ्री सूचियों (फ्री लिस्ट्स), साइज़ क्लासेज, थ्रेड-लोकल एलोकेशन और फ्रैग्मेंटेशन को सिस्टम-इंटरव्यू चर्चा बिंदुओं के रूप में मानती है। Redis का प्रोडक्शन दस्तावेज़ उसी अवलोकनीय लक्षण का वर्णन करता है: लॉजिकल डेटा को हटाने से RSS अपने पिछले पीक के करीब रह सकता है क्योंकि मुक्त हिस्से (फ्री चंक्स) एलोकेटर के लिए उपलब्ध रहते हैं या पेजों में अभी भी लाइव ऑब्जेक्ट्स होते हैं। लिनक्स और glibc दस्तावेज़ फिर साक्ष्य-आधारित उत्तर के लिए आवश्यक मापन और नियंत्रण सतह प्रदान करते हैं। ये स्रोत प्रासंगिकता और कार्यप्रणाली स्थापित करते हैं; वे यह साबित नहीं करते कि कोई विशेष कंपनी इस सटीक प्रॉम्प्ट का उपयोग करती है या इसे एक विशेष आवृत्ति पर पूछा जाता है।

साक्षात्कारकर्ता क्या मूल्यांकन कर रहा है

पहला संकेत यह है कि क्या आप ओनरशिप को रेजिडेंसी से अलग करते हैंfree(p) के बाद, कॉलर के पास अब उस एलोकेशन का स्वामित्व नहीं होता है और एलोकेटर उस ब्लॉक का पुन: उपयोग कर सकता है। C एलोकेशन अनुबंध munmap, कम RSS, या तत्काल फिजिकल-पेज रीक्लेमेशन का वादा नहीं करता है। यह कहना कि "free हमेशा मेमोरी लौटाता है" या "free कभी मेमोरी नहीं लौटाता" एलोकेटर-विशिष्ट पाथ्स को अनदेखा करता है।

दूसरा संकेत यह है कि क्या आप चार मापन लेयर्स (मेज़रमेंट लेयर्स) को अलग करते हैं:

  • एप्लिकेशन लाइव एलोकेशन्स;
  • एलोकेटर इन-यूज़, फ्री, मैप्ड, और रिलीज़ करने योग्य बाइट्स;
  • प्रोसेस मैपिंग्स और रेजिडेंट पेजेस;
  • cgroup-व्यापी चार्जेज और दबाव (प्रेशर)।

RSS कोई लाइव-हीप काउंटर नहीं है। लिनक्स VmRSS को RssAnon + RssFile + RssShmem के रूप में परिभाषित करता है। फ़ाइल मैपिंग्स, शेयर्ड मेमोरी, स्टैक्स, एलोकेटर मेटाडेटा और नेटिव लाइब्रेरीज़ सभी इस अंतर को बढ़ा सकते हैं। इसलिए एक हीप प्रोफाइल और एक top रीडिंग किसी लीक को साबित या गलत साबित नहीं कर सकती है।

तीसरा संकेत डायग्नोस्टिक भेदभाव (डायग्नोस्टिक डिस्क्रिमिनेशन) है। एक लीक एलोकेशन्स को रीचेबल या अन्यथा लाइव छोड़ देता है। रिटेंशन का मतलब है कि कुशल पुन: उपयोग के लिए फ्री मेमोरी मैप्ड रहती है। फ्रैग्मेंटेशन का मतलब है कि एलोकेटर के पास फ्री बाइट्स हैं लेकिन वह पेज-साइज़ के रिलीज़ करने योग्य क्षेत्र नहीं बना सकता है, अक्सर इसलिए क्योंकि कुछ लाइव ऑब्जेक्ट्स पेजों को पिन करते हैं या फ्री स्पेस एरेनास और साइज़ क्लासेज के बीच विभाजित होता है। ये स्थितियां सह-अस्तित्व में हो सकती हैं, इसलिए उम्मीदवार को एक अनुपात से अनुमानित लेबल के बजाय नियंत्रित अवलोकनों की आवश्यकता होती है।

अंत में, साक्षात्कारकर्ता एक प्रोडक्शन निर्णय चाहता है। एरेना काउंट को कम करना, आक्रामक रूप से ट्रिम करना, या एलोकेटर को बदलना लॉक्स, पेज फॉल्ट्स, सिस्टम कॉल्स या CPU वर्क को जोड़ते हुए रेजिडेंट मेमोरी को कम कर सकता है। एक मजबूत उत्तर कैनरी, वर्कलोड रीप्ले, स्वीकृति थ्रेशोल्ड और रोलबैक के साथ 8 GiB सीमा और 120 ms p99 SLO दोनों की सुरक्षा करता है।

उत्तर देने से पहले स्पष्ट करने योग्य प्रश्न

  • कौन सा एलोकेटर और वर्ज़न सक्रिय है? glibc ट्यूनेबल्स और malloc_trim jemalloc, tcmalloc, mimalloc, एक भाषा रनटाइम एलोकेटर, या सांख्यिकीय रूप से लिंक किए गए रिप्लेसमेंट का वर्णन नहीं करते हैं। इसके काउंटरों का उपयोग करने से पहले लोड किए गए एलोकेटर और परिनियोजन (डिप्लॉयमेंट) इमेज की पुष्टि करें।
  • सटीक रूप से क्या 1.1 GiB रिपोर्ट करता है? एक सैंपल किया गया हीप प्रोफाइल, सटीक एलोकेटर काउंटर, मैनेज्ड-रनटाइम हीप, और बिजनेस कैश मेट्रिक विभिन्न बाइट्स को कवर करते हैं। पुष्टि करें कि क्या नेटिव लाइब्रेरीज़, स्टैक्स, डायरेक्ट मैपिंग्स और एलोकेटर मेटाडेटा शामिल हैं।
  • कौन सा RSS घटक अधिक बना रहता है? RssAnon हीप, स्टैक्स और अज्ञात (अनाम/एनोनिमस) मैपिंग्स की ओर संकेत करता है; RssFile फ़ाइल-समर्थित मैपिंग्स की ओर; RssShmem साझा (शेयर्ड) मेमोरी की ओर। यदि वृद्धि एनोनिमस नहीं है, तो एलोकेटर ट्यूनिंग पहला सही कदम नहीं है।
  • क्या प्रत्येक समान बैच के बाद यह पठार (प्लेटो) दोहराता है या बढ़ता है? एक स्थिर हाई-वॉटर प्लेटो जो अगले बैच को बिना किसी अन्य 5 GiB वृद्धि के सेवा प्रदान करता है, पुनर्चक्रण (रीयूज़) का सुझाव देता है। लाइव एलोकेशन्स या RSS में एक सीढ़ीदार वृद्धि (स्टेयरकेस) को लीक, वर्कलोड या मैपिंग स्पष्टीकरण की आवश्यकता होती है।
  • क्या थ्रेड काउंट, एलोकेशन साइज़, या ऑब्जेक्ट लाइफटाइम बदले? कई थ्रेड्स और क्रॉस-थ्रेड फ़्रीज़ एरेनास या कैश में ब्लॉक्स को फैला सकते हैं। मिश्रित अल्पकालिक और दीर्घकालिक ऑब्जेक्ट्स कई अन्यथा फ्री पेजों पर एक उत्तरजीवी छोड़ सकते हैं।
  • क्या cgroup वास्तव में दबाव में है? memory.current, memory.events, PSI, स्वैप, और पड़ोसी प्रोसेसेस की तुलना करें। पर्याप्त हेडरूम के साथ उच्च RSS एक दक्षता का मुद्दा हो सकता है; बार-बार memory.high इवेंट्स या 8 GiB से निकटता रिलीज़ व्यवहार को परिचालन रूप से अत्यावश्यक बनाती है।
  • अगला बैच कब चलेगा? 4 GiB को पांच मिनट के लिए पुन: प्रयोज्य रखना तर्कसंगत हो सकता है। इसे एक सख्त सीमा के तहत बारह निष्क्रिय घंटों तक बनाए रखना एक पोस्ट-बैच पर्ज या एक अलग एलोकेशन पैटर्न को उचित ठहरा सकता है।
  • कौन सा रिग्रेशन बजट स्वीकार्य है? यदि सेवा 2% अधिक CPU खर्च कर सकती है लेकिन p99 में 5 ms नहीं जोड़ सकती है, या यदि मेमोरी लागत कोल्ड-एलोकेशन लेटेंसी से अधिक मायने रखती है, तो उपाय बदल जाता है।

30-सेकंड उत्तर रूपरेखा

"free() एलोकेटर को एक ब्लॉक लौटाता है; यह अपने पेजों को अनमैप करने का वादा नहीं करता है, इसलिए RSS बिना किसी लीक के अधिक बना रह सकता है। मैं एक बैच टाइमलाइन को संरेखित करूंगा और लाइव-एलोकेशन प्रोफाइल, एलोकेटर इन-यूज़ और फ्री बाइट्स, RssAnon, प्रति-मैपिंग smaps, और cgroup उपयोग की तुलना करूंगा। फिर मैं बैच को तीन बार दोहराऊंगा। बढ़ते हुए लाइव बाइट्स एक लीक का संकेत देते हैं; स्थिर लाइव बाइट्स और एक फ्लैट RSS जिसका अगला बैच पुन: उपयोग करता है, रिटेंशन का संकेत देता है; प्रचुर मात्रा में एलोकेटर-फ्री बाइट्स के साथ बहुत कम रिलीज़ करने योग्य मेमोरी और जीवित ऑब्जेक्ट्स द्वारा पिन किए गए पेजेस फ्रैग्मेंटेशन का संकेत देते हैं। मैं malloc_trim(0) का उपयोग केवल glibc कैनरी प्रयोग के रूप में करूंगा, न कि एक पूर्ण समाधान के रूप में। अंतिम उपाय ओनरशिप सुधार, लाइफटाइम पृथक्करण, एक सीमित पोस्ट-बैच ट्रिम, परीक्षित एरेना ट्यूनिंग, या एक एलोकेटर परिवर्तन हो सकता है, जिसे केवल तभी स्वीकार किया जाएगा जब एक प्रोडक्शन-आकार का रीप्ले 120 ms p99 को तोड़े बिना मेमोरी लक्ष्य से नीचे रहता है।"

चरण-दर-चरण गहन विश्लेषण

चरण 1: एक मेमोरी टाइमलाइन बनाएं

डिप्लॉयमेंट वर्ज़न, PID, cgroup पाथ, थ्रेड काउंट, अनुरोध और बैच वॉल्यूम, एलोकेशन-रेट डिस्ट्रीब्यूशन, लाइव बाइट्स, RSS कंपोनेंट्स, memory.current, memory.peak, प्रेशर, और OOM इवेंट्स रिकॉर्ड करें। बैच से पहले, 6 GiB पीक पर, डी-एलोकेशन के तुरंत बाद, और 20-मिनट की निष्क्रिय विंडो के दौरान सैंपल लें। एक अलग PID, cgroup, या वर्कलोड तुलना को अमान्य कर देता है।

पहला प्रश्न परिचालन है: क्या RSS केवल अधिक है, या सेवा एक सीमा के करीब पहुंच रही है और दबाव में रीक्लेम कर रही है? 8 GiB की सीमा के भीतर 5.2 GiB पर, अन्य cgroup शुल्कों से पहले प्रत्यक्ष हेडरूम 2.8 GiB है। वह घटाव केवल एक स्केल चेक है क्योंकि cgroup इस प्रोसेस के एनोनिमस RSS से परे मेमोरी का भी हिसाब रखता है। वास्तविक डोमेन के लिए memory.current और memory.stat का उपयोग करें।

चरण 2: एलोकेटर-टू-कर्नेल सीमा को समझाएं

एक एलोकेटर ऑपरेटिंग सिस्टम से बड़े क्षेत्रों का अनुरोध करता है और उन्हें चंक्स में विभाजित करता है। glibc सामान्य एरेनास का विस्तार कर सकता है और पर्याप्त रूप से बड़े एलोकेशन्स के लिए अलग एनोनिमस मैपिंग बना सकता है। जब कोई एप्लिकेशन एक चंक को मुक्त करता है, तो एलोकेटर पहले उस चंक को पुन: प्रयोज्य बनाता है। यह आसन्न फ्री चंक्स को जोड़ (कोएलेस) सकता है, उन्हें डिब्बे (बिन्स) या कैश में रख सकता है, भविष्य के सिस्टम कॉल्स से बचने के लिए उन्हें बनाए रख सकता है, या उपयुक्त पेजों को रिलीज़ कर सकता है।

स्वतंत्र रूप से मैप किए गए बड़े चंक्स को अक्सर मुक्त होने पर अनमैप किया जा सकता है। सामान्य हीप मेमोरी अधिक कठिन होती है। किसी क्षेत्र के बीच में एक फ्री ब्लॉक हीप के अंत को सिकोड़ नहीं सकता है, और एक पेज जिसमें एक भी लाइव रॉ-पॉइंटर ऑब्जेक्ट शामिल है, उस ऑब्जेक्ट को स्थानांतरित किए बिना अनमैप नहीं किया जा सकता है। C और C++ एलोकेटर आमतौर पर मनमाने लाइव ऑब्जेक्ट्स को कॉम्पैक्ट नहीं कर सकते क्योंकि एप्लिकेशन पॉइंटर्स अमान्य हो जाएंगे।

यह तीन अलग-अलग प्रकार के ओवरहेड उत्पन्न करता है:

  • आंतरिक फ्रैग्मेंटेशन (Internal fragmentation): 20-बाइट का अनुरोध एक बड़े संरेखित (अलाइन्ड) या साइज़-क्लास ब्लॉक का उपभोग कर सकता है।
  • बाहरी या पेज-स्तरीय फ्रैग्मेंटेशन (External or page-level fragmentation): फ्री स्पेस मौजूद है, लेकिन यह विभाजित या पिन किया गया है ताकि पूरे पेजों को रिलीज़ न किया जा सके।
  • जानबूझकर किया गया रिटेंशन (Intentional retention): पूरे या आंशिक पेज मैप किए रहते हैं क्योंकि एलोकेटर पुन: उपयोग की उम्मीद करता है और रिलीज़/पुन: प्राप्ति की एक लागत होती है।

ये लेबल तंत्रों का वर्णन करते हैं, न कि एकल RSS / live_bytes अनुपात से निकाले गए निष्कर्षों का।

चरण 3: चार मापन लेयर्स का मिलान करें

लिनक्स प्रोसेस अकाउंटिंग के साथ प्रारंभ करें:

text
VmRSS = RssAnon + RssFile + RssShmem

विस्तृत विभाजन के लिए /proc/PID/status और कुल RSS, PSS, एनोनिमस, फ़ाइल, शेयर्ड, और लेज़ी-फ्री जानकारी के लिए /proc/PID/smaps_rollup पढ़ें। /proc/PID/smaps का उपयोग केवल तभी करें जब आपको उन विशेष एनोनिमस या फ़ाइल-समर्थित मैपिंग्स की पहचान करने की आवश्यकता हो जो बढ़ी हैं। एक बार का pmap या RSS कुल सिंक्रोनाइज़्ड डेल्टास की तुलना में कम जानकारीपूर्ण होता है।

फिर एलोकेटर सांख्यिकी जोड़ें। glibc में, mallinfo2 sbrk के माध्यम से प्राप्त बाइट्स, मैप्ड चंक्स में बाइट्स, कॉलर्स को दिए गए बाइट्स, फ्री बाइट्स, और टॉप रिलीज़ करने योग्य चंक को उजागर कर सकता है। ये फ़ील्ड प्रत्येक एलोकेशन स्रोत को कवर नहीं करते हैं और इन्हें लगातार सैंपल किया जाना चाहिए, लेकिन वे यह उत्तर देने में मदद करते हैं कि क्या एलोकेटर के पास अधिकांश एनोनिमस अंतर का स्वामित्व है। एप्लिकेशन के एलोकेटर-नेटिव प्रोफाइलिंग को प्राथमिकता दें जब यह अधिक पूर्ण मैप्ड, सक्रिय, रेजिडेंट, रिटेन्ड, और प्रति-साइज़-क्लास डेटा प्रदान करता है।

अंत में, cgroup v2 के साथ मिलान करें। cgroup अपने पदानुक्रम (हाइरार्की) में सभी चार्ज की गई मेमोरी को शामिल करता है, इसलिए यह एक प्रोसेस के RSS से अधिक हो सकता है या किसी भिन्न कारण से बदल सकता है। memory.current और memory.stat की तुलना प्रोसेस साक्ष्य के साथ करें, बजाय इसके कि उन्हें जबरन बराबर किया जाए।

चरण 4: तीन-चक्र पुनर्चक्रण (रीयूज़) प्रयोग का उपयोग करें

समान 64-थ्रेड समवर्तीता (कंकरेंसी) और इनपुट-साइज़ डिस्ट्रीब्यूशन के साथ प्रोडक्शन-आकार के कैनरी पर एक ही बैच को तीन बार चलाएं। प्रत्येक बैच के बाद, समान 20 मिनट प्रतीक्षा करें और समान काउंटरों को कैप्चर करें।

आकृतियों की व्याख्या करें:

अवलोकनमजबूत परिकल्पनाअगला परीक्षण
प्रत्येक निष्क्रिय अवधि के बाद लाइव एलोकेशन्स बढ़ते हैंलीक या एप्लिकेशन रिटेंशनलाइव-ऑब्जेक्ट और एलोकेशन-स्टैक प्रोफाइल की तुलना करें
लाइव बाइट्स 1.1 GiB पर लौटते हैं; RSS 5.2 GiB के करीब रहता है; बाद के बैच बिना किसी समान RSS वृद्धि के एलोकेट होते हैंपुन: प्रयोज्य एलोकेटर रिटेंशनपेज फॉल्ट्स, एलोकेशन लेटेंसी, और एलोकेटर फ्री बाइट्स को मापें
लाइव बाइट्स फ्लैट रहते हैं; एलोकेटर फ्री बाइट्स अधिक हैं; रिलीज़ करने योग्य बाइट्स कम रहते हैं; लाइफटाइम या साइज़ मिक्स में बदलाव पठार को बदलते हैंफ्रैग्मेंटेशन या एरेना फैलाव (डिस्पर्शन)साइज़ क्लासेज, एरेनास, क्रॉस-थ्रेड फ़्रीज़, और पिन की गई मैपिंग्स का निरीक्षण करें
RssFile या RssShmem अधिकांश अंतर की व्याख्या करता हैफ़ाइल मैपिंग या शेयर्ड-मेमोरी लाइफसाइकिलमैपिंग्स और स्वामियों का पता लगाएं; malloc ट्यून करना बंद करें
लाइव बाइट्स और गैर-हीप एनोनिमस मैपिंग्स दोनों बढ़ते हैंएक से अधिक कारणहीप और नेटिव मैपिंग्स को अलग से प्रोफाइल करें

एक पठार (प्लेटो) स्वचालित रूप से हानिरहित नहीं होता है। यदि अगला बैच 8 GiB से ऊपर पहुंच जाता है क्योंकि पुराने रिटेन्ड पेजेस इसके नए साइज़ डिस्ट्रीब्यूशन की सेवा नहीं कर सकते हैं, तो स्थिर लॉजिकल डेटा के बावजूद सेवा विफल हो सकती है। इसके विपरीत, एक उच्च पठार जो उसी वर्कलोड को कुशलतापूर्वक संतुष्ट करता है, जबरन रिलीज़ और बार-बार के फॉल्ट्स की तुलना में बेहतर हो सकता है।

चरण 5: ट्रिम का एक सीमित डायग्नोस्टिक के रूप में उपयोग करें

glibc कैनरी पर, पोस्ट-बैच सीमा पर एक बार malloc_trim(0) को कॉल करें और इसके रिटर्न वैल्यू, RSS कंपोनेंट्स, एलोकेटर लाइव बाइट्स, पेज फॉल्ट्स, CPU, और बाद की अनुरोध लेटेंसी को रिकॉर्ड करें। GNU इंटरफ़ेस फ्री हीप मेमोरी को रिलीज़ करने का प्रयास करता है और sbrk या madvise का उपयोग कर सकता है; यह किसी विशेष RSS कमी का वादा नहीं करता है।

यदि लाइव एलोकेशन्स 1.1 GiB पर बने रहने के दौरान RssAnon काफी गिर जाता है, तो कुछ एलोकेटर-स्वामित्व वाले पेज रिलीज़ करने योग्य थे। यह निदान को संकीर्ण करता है, लेकिन यह साबित नहीं करता है कि प्रोडक्शन में ट्रिम को कॉल करना सबसे अच्छी नीति है। यदि RSS शायद ही बदलता है, तो पूरे फ्री पेज अनुपलब्ध हो सकते हैं, वृद्धि glibc के बाहर रह सकती है, या मेट्रिक में विभिन्न मैपिंग्स शामिल हो सकती हैं। ट्रिम करने में विफलता किसी लीक को साबित नहीं करती है।

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

चरण 6: साबित कारण के साथ उपाय का मिलान करें

  • लीक: ओनिंग रेफरेंस, कैश बाउंड, मिसिंग फ्री, या लाइब्रेरी लाइफसाइकिल को ठीक करें। ट्रिमिंग लाइव मेमोरी को रिलीज़ करने योग्य नहीं बनाती है।
  • निकट-अवधि के पुन: उपयोग के साथ जानबूझकर रिटेंशन: इसे बनाए रखें, मापे गए पीक के लिए प्रावधान करें, और RSS को लाइव बाइट्स से मेल खाने के लिए मजबूर करने के बजाय बार-बार होने वाले स्टेयरकेस पर अलर्ट करें।
  • लाइफटाइम-संचालित फ्रैग्मेंटेशन: अल्पकालिक बैच ऑब्जेक्ट्स को दीर्घकालिक सेवा स्थिति से अलग करें, एक बैच एरेना या क्षेत्र का उपयोग करें जिसे एक इकाई के रूप में रिलीज़ किया जा सकता है, और कई क्षणिक पेजों में एक दीर्घकालिक ऑब्जेक्ट को इंटरलीव करने से बचें।
  • एरेना या थ्रेड-कैश फैलाव: कम एरेनास, एलोकेशन हॉटस्पॉट पर कम समवर्तीता, या एक अलग ओनरशिप पैटर्न का परीक्षण करें। कम एरेनास मेमोरी बचा सकते हैं लेकिन विवाद (कंटेंशन) बढ़ा सकते हैं।
  • सख्त सीमा के तहत लंबा निष्क्रिय चरण: दर सीमाओं (रेट लिमिट्स) और रोलबैक ध्वज के साथ एक स्पष्ट पोस्ट-बैच ट्रिम या एलोकेटर-विशिष्ट पर्ज का परीक्षण करें।
  • एलोकेटर बेमेल (मिसमैच): सटीक ट्रेस के तहत उपयुक्त विकल्प के साथ glibc की तुलना करें। Microsoft Research का mimalloc डिज़ाइन मुख्य ट्रेडऑफ़ को दर्शाता है: थ्रेड-लोकल पेज स्केलेबिलिटी और लोकैलिटी में सुधार करते हैं, जबकि पृथक स्वामित्व उस मेमोरी को बनाए रख सकता है जिसे दूसरा थ्रेड तुरंत पुन: उपयोग नहीं कर सकता है।

glibc के arena_max, trim_threshold, और mmap_threshold प्रयोग हैं, जादुई स्थिरांक (मैजिक कांस्टेंट्स) नहीं। उन्हें सेट करने से व्यवहार अधिक स्थिर हो जाता है और विवाद, मैपिंग काउंट, रिलीज़ आवृत्ति और syscall लागत बदल सकती है। एक समय में एक कारक बदलें और रोलबैक के रूप में मूल इमेज को बनाए रखें।

चरण 7: मेमोरी और लेटेंसी को एक साथ मान्य करें

प्रोडक्शन-आकार के हार्डवेयर पर 30 समान चक्रों को दोबारा चलाएं (रीप्ले करें)। संख्या 30 एक अभ्यास परीक्षण विंडो है, कोई सार्वभौमिक आवश्यकता नहीं है। लाइव एलोकेशन्स, एलोकेटर मैप्ड/फ्री/रिलीज़ करने योग्य बाइट्स, RssAnon, कुल RSS, memory.current, प्रेशर, पेज फॉल्ट्स, एलोकेशन लेटेंसी, CPU, थ्रूपुट, और p50/p99 अनुरोध लेटेंसी को ट्रैक करें।

इस परिदृश्य के लिए उदाहरण स्वीकृति मानदंड हो सकते हैं: 20 मिनट के भीतर पोस्ट-आइडल RssAnon 2.2 GiB पर या उससे कम, 30 चक्रों में कोई ऊपर की ओर सीढ़ीदार वृद्धि नहीं, कोई OOM या निरंतर दबाव नहीं, p99 120 ms पर या उससे कम, और 3% से अधिक CPU रिग्रेशन नहीं। ये थ्रेशोल्ड सेवा के वास्तविक बजट के साथ बदलने के लिए अभ्यास मान्यताएं हैं। एक उपाय जो 2.2 GiB तक पहुंचता है लेकिन p99 को 145 ms तक धकेलता है, विफल हो जाता है; एक उपाय जो लेटेंसी को सुरक्षित रखता है लेकिन फिर भी अगले वैध साइज़ मिक्स के तहत 8 GiB सीमा के करीब पहुंचता है, वह भी विफल हो जाता है।

उच्च-गुणवत्ता वाला नमूना उत्तर

"मैं केवल RSS से इसे लीक नहीं कहूंगा। free() किसी ब्लॉक के एप्लिकेशन स्वामित्व को समाप्त करता है, लेकिन glibc पुन: उपयोग के लिए उस ब्लॉक को एरेना में रख सकता है, और कुछ लाइव ऑब्जेक्ट्स अन्यथा फ्री पेजों को रेजिडेंट रख सकते हैं। मैं पहले यह सत्यापित करूंगा कि 1.1 GiB संख्या नेटिव लाइव एलोकेशन्स को कवर करती है, फिर एक पूर्ण बैच के माध्यम से इसे RssAnon, RssFile, RssShmem, smaps मैपिंग्स, एलोकेटर सांख्यिकी और cgroup चार्ज के साथ संरेखित करूंगा।

मैं उसी बैच को तीन बार रीप्ले करूंगा। यदि प्रत्येक 20-मिनट की निष्क्रिय अवधि के बाद लाइव एलोकेशन्स बढ़ते हैं, तो मैं लाइव-ऑब्जेक्ट प्रोफाइल का अंतर (diff) देखूंगा और ओनरशिप पाथ को ठीक करूंगा। यदि लाइव बाइट्स 1.1 GiB पर रहते हैं, RSS 5.2 GiB के करीब रहता है, और अगला बैच बिना किसी अन्य वृद्धि के उस स्थान का पुन: उपयोग करता है, तो रिटेंशन अधिक मजबूत स्पष्टीकरण है। यदि एलोकेटर-फ्री बाइट्स अधिक हैं लेकिन रिलीज़ करने योग्य पेज कम रहते हैं और ऑब्जेक्ट लाइफटाइम या 64-थ्रेड कंकरेंसी के साथ पठार बदलता है, तो मैं फ्रैग्मेंटेशन और एरेना फैलाव की जांच करूंगा।

केवल-glibc डायग्नोस्टिक के रूप में, मैं बैच के बाद कैनरी पर एक बार malloc_trim(0) को कॉल करूंगा। अपरिवर्तित लाइव बाइट्स के साथ एक निचला RssAnon दर्शाता है कि कुछ एलोकेटर पेज रिलीज़ करने योग्य थे; यह प्रत्येक अनुरोध को ट्रिम करने का औचित्य साबित नहीं करता है। फिर मैं सबसे छोटा कारण-विशिष्ट परिवर्तन चुनूंगा: एक लीक की मरम्मत करना, बैच लाइफटाइम को एक रिलीज़ करने योग्य क्षेत्र में अलग करना, या एक सीमित पोस्ट-बैच ट्रिम या एरेना सेटिंग को कैनरी करना। मैं 30 चक्रों को रीप्ले करूंगा और परिवर्तन को केवल तभी स्वीकार करूंगा जब पोस्ट-आइडल मेमोरी सहमत लक्ष्य को पूरा करती है, RSS सीढ़ीदार नहीं बनता है, cgroup सुरक्षित रहता है, और p99 120 ms के भीतर रहता है।"

सामान्य गलतियां

  • 4.1 GiB अंतर को लीक कहना → RSS में एलोकेटर-फ्री पेज और गैर-हीप मैपिंग्स शामिल हैं → सिंक्रोनाइज़्ड प्रोफाइल के साथ लाइव एलोकेशन्स या रिटेन्ड ओनरशिप में वृद्धि को सिद्ध करें।
  • दावा करना कि free() हमेशा RSS को कम करता है → एक मुक्त किया गया चंक एरेना में रह सकता है या लाइव चंक्स के साथ एक पेज साझा कर सकता है → पुनर्चक्रण, संपूर्ण-पेज रिलीज़, और स्वतंत्र रूप से मैप किए गए एलोकेशन्स का वर्णन करें।
  • दावा करना कि free() कभी मेमोरी वापस नहीं करता है → एलोकेटर बड़ी मैपिंग्स को अनमैप कर सकते हैं, टॉप चंक्स को ट्रिम कर सकते हैं, या पूरे फ्री पेजों को हटा (advise away) सकते हैं → बताएं कि रिलीज़ एलोकेटर, लेआउट, और नीति पर निर्भर करता है।
  • सबूत के रूप में एक फ्रैग्मेंटेशन अनुपात का उपयोग करना → एक हालिया पीक, फ़ाइल मैपिंग, कैश, या जानबूझकर किया गया रिटेंशन इसे बढ़ा सकता है → बार-बार चक्रों में लाइव, फ्री, मैप्ड, रेजिडेंट, और रिलीज़ करने योग्य बाइट्स की तुलना करें।
  • प्रत्येक अनुरोध पर malloc_trim(0) को कॉल करना → जबरन रिलीज़ सिस्टम कॉल्स, फॉल्ट्स और टेल लेटेंसी जोड़ सकती है → एक प्राकृतिक निष्क्रिय सीमा पर इसका एक बार परीक्षण करें और अगले एलोकेशन बर्स्ट को मापें।
  • 64 थ्रेड्स होने के कारण arena_max को एक पर सेट करना → लॉक विवाद बढ़ते हुए मेमोरी गिर सकती है → समान समवर्तीता के तहत उम्मीदवार मानों का परीक्षण करें और p99 की रक्षा करें।
  • बेंचमार्क हेडलाइन से एलोकेटर बदलना → एलोकेशन साइज़, लाइफटाइम और क्रॉस-थ्रेड-फ्री पैटर्न परिणाम निर्धारित करते हैं → रोलबैक और मेमोरी व लेटेंसी मानदंड दोनों के साथ सटीक ट्रेस का A/B परीक्षण करें।
  • cgroup अकाउंटिंग की अनदेखी करना → एक प्रोसेस का RSS संपूर्ण मेमोरी डोमेन नहीं है → प्रोसेस मेट्रिक्स के साथ memory.current, memory.stat, वंशजों (डिसेंडेंट्स), और प्रेशर का मिलान करें।

अनुवर्ती प्रश्न और उत्तर

यदि malloc_trim(0) RSS को 5.2 GiB से 1.8 GiB तक गिरा देता है, तो आपने क्या साबित किया है?

आपने दिखाया है कि glibc के पास उस समय काफी मात्रा में पेज-रिलीज़ करने योग्य मेमोरी थी और उच्च RSS पूरी तरह से लाइव एप्लिकेशन डेटा नहीं था। आपने छोटे लीक की अनुपस्थिति, रिटेंशन का कारण, या बार-बार ट्रिमिंग की सुरक्षा को साबित नहीं किया है। नीति चुनने से पहले वर्कलोड को फिर से चलाएं और पेज फॉल्ट्स, CPU, एलोकेशन लेटेंसी और p99 को मापें।

यदि ट्रिम शून्य लौटाता है और RSS नहीं बदलता है, तो क्या यह एक लीक है?

नहीं। फ्री स्पेस उन पेजों में वितरित हो सकता है जिनमें अभी भी लाइव चंक्स हैं, मेमोरी किसी अन्य एलोकेटर या मैपिंग में रखी जा सकती है, या कोई रिलीज़ करने योग्य glibc पेज मौजूद नहीं हो सकते हैं। लाइव प्रोफाइल, एलोकेटर फ्री और रिलीज़ करने योग्य बाइट्स, और smaps ओनरशिप की तुलना करें। एक लीक के लिए लाइव या रिटेन्ड एलोकेशन्स के बढ़ने के सबूत की आवश्यकता होती है, न कि केवल असफल ट्रिमिंग की।

क्या होगा यदि RSS स्थिर रहता है लेकिन memory.current बढ़ता रहता है?

हीप के बजाय cgroup डेल्टा की जांच करें। memory.stat फ़ाइल कैश, shmem, सॉकेट, या कर्नेल मेमोरी को प्रकट कर सकता है, और cgroup में अन्य प्रोसेसेस या वंशज शामिल हो सकते हैं। पदानुक्रम और मैपिंग स्वामित्व की पुष्टि करें। glibc को ट्यून करना क्योंकि एक प्रोसेस का RSS फ्लैट है, गलत लेयर को लक्षित करेगा।

glibc को एक एरेना का उपयोग करने के लिए बाध्य क्यों न करें?

एक एरेना फैलाव को कम कर सकता है लेकिन अधिक एलोकेशन कार्य को क्रमबद्ध (सीरियलाइज़) करता है। 64 थ्रेड्स के साथ, यह लॉक विवाद और p99 रिग्रेशन के लिए रेजिडेंट मेमोरी का आदान-प्रदान कर सकता है। वास्तविक एलोकेशन ट्रेस के तहत कई सीमित एरेना काउंट्स का परीक्षण करें, एलोकेटर विवाद और लेटेंसी को कैप्चर करें, और सबसे छोटी संख्या का चयन करें जो दोनों बजटों को संतुष्ट करती है।

बैच एरेना या रीजन एलोकेटर कब बेहतर होगा?

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

आप एक रिप्लेसमेंट एलोकेटर का मूल्यांकन कैसे करेंगे?

एलोकेटर लिंकेज, समान इनपुट ट्रेस, थ्रेड काउंट, CPU प्लेसमेंट, वार्म-अप, और 30-चक्र विंडो को छोड़कर उसी बिल्ड का उपयोग करें। पीक और पोस्ट-आइडल RSS, लाइव-टू-रेजिडेंट गैप, एलोकेशन थ्रूपुट, CPU, पेज फॉल्ट्स, p50/p99, और 8 GiB सीमा के करीब विफलता व्यवहार की तुलना करें। एक डिप्लॉयमेंट रोलबैक के पीछे विजेता का कैनरी परीक्षण करें; केवल कम औसत RSS पर्याप्त नहीं है।

सार्वजनिक स्रोत

संबंधित प्रश्न