Go में मेमोरी और गार्बेज कलेक्टर (GC): GC कैसे संसाधनों का प्रबंधन करता है

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

Go में मेमोरी और गार्बेज कलेक्टर (GC): GC से कैसे निपटें

\n

क्या आपने कभी सोचा है कि आपके Go एप्लिकेशन की मेमोरी कहाँ जाती है? खासकर जब वह गीगाबाइट्स खाने लगे, और आप सिर्फ JSON पार्स कर रहे हों? परिचित लग रहा है? Go में गार्बेज कलेक्टर (GC) की दुनिया में आपका स्वागत है — एक रहस्यमयी तंत्र जो या तो आपके प्रोजेक्ट को बचाता है या उसे धीमा कर देता है। आज हम जानेंगे कि Go में मेमोरी कैसे काम करती है, GC कैसे तय करता है कि कब सफाई करनी है, और "STW के इंतज़ार" के जाल से कैसे बचें।

\n

अगर आप कुछ महीनों से Go में कोड लिख रहे हैं, तो आपने यह ज़रूर देखा होगा: अचानक रुकावटें, मेमोरी की खपत बढ़ना, प्रोफाइल में रहस्यमयी gc pause। आइए हुड के नीचे झाँकें और समझें कि Go में मेमोरी को समझदारी से कैसे मैनेज करें।

\n\n

Go में मेमोरी की संरचना: हीप और स्टैक

\n

गार्बेज कलेक्टर पर बात करने से पहले, यह समझ लें कि Go में डेटा कहाँ रहता है। C जैसी भाषाओं के विपरीत, जहाँ आप खुद malloc/free का ध्यान रखते हैं, Go स्वचालित मेमोरी प्रबंधन का उपयोग करता है। लेकिन इसका मतलब यह नहीं कि सब कुछ एक ही ढेर में चला जाता है।

\n

Go में मेमोरी के दो मुख्य क्षेत्र हैं:

\n
    \n
  • स्टैक (stack) — लोकल वेरिएबल्स के लिए तेज़, स्वचालित रूप से प्रबंधित मेमोरी। हर goroutine का अपना स्टैक होता है (2 KB से शुरू होकर डायनामिक रूप से बढ़ता है)।
  • \n
  • हीप (heap) — धीमी लेकिन लचीली मेमोरी, उन डेटा के लिए जो फंक्शन कॉल के बाद भी जीवित रहते हैं।
  • \n
\n

मुख्य सवाल: क्या हीप में जाता है और क्या स्टैक पर रहता है? इसका जवाब escape analysis देता है — Go कंपाइलर का एक स्मार्ट तंत्र। यह विश्लेषण करता है कि क्या वेरिएबल फंक्शन की सीमा से "बाहर भाग" रहा है। अगर हाँ — तो वह हीप में जाता है। अगर नहीं — स्टैक पर रहता है, और GC को उसके बारे में पता भी नहीं चलता।

\n

उदाहरण:

\n
package main\n\nfunc createPointer() *int {\n    x := 42\n    return &x // x "भाग" गया — हीप में जाएगा\n}\n\nfunc noEscape() int {\n    x := 42\n    return x // x स्टैक पर ही रहेगा\n}\n
\n

पहले मामले में, कंपाइलर देखता है कि x का पॉइंटर बाहर लौटाया जा रहा है, और वेरिएबल को हीप में रखता है। दूसरे में — सब कुछ सरल और तेज़ है। यही है Go में मेमोरी प्रबंधन सूक्ष्म स्तर पर।

\n\n

Go में गार्बेज कलेक्टर: यह कैसे काम करता है

\n

अब बात करते हैं मुख्य किरदार की — गार्बेज कलेक्टर (GC) की। Go में समानांतर, तिरंगा, गैर-इंक्रीमेंटल कलेक्टर का उपयोग "mark-and-sweep" एल्गोरिदम के साथ किया जाता है। डरावना लगता है? असल में यह बहुत तार्किक है।

\n

Go में GC तीन चरणों से गुज़रता है:

\n
    \n
  1. Mark Setup (STW) — write barrier चालू करने के लिए छोटा विराम। आमतौर पर 10-30 माइक्रोसेकंड लगता है।
  2. \n
  3. Marking (Concurrent) — मुख्य काम: GC ऑब्जेक्ट ग्राफ को ट्रैवर्स करता है और जीवित ऑब्जेक्ट्स को चिह्नित करता है। यह आपके कोड के समानांतर चलता है।
  4. \n
  5. Sweep (Concurrent + STW) — मृत ऑब्जेक्ट्स की सफाई। आंशिक रूप से समानांतर, लेकिन अंतिम सिंक्रोनाइज़ेशन में छोटा विराम हो सकता है।
  6. \n
\n

Go में GC की मुख्य विशेषता — यह डीफ़्रैग्मेंटेशन नहीं करता। इसका मतलब है कि सफाई के बाद मेमोरी फ़्रैग्मेंटेड हो सकती है, लेकिन Go खाली ब्लॉक्स को ट्रैक करने के लिए बिट मैप का उपयोग करता है, जिससे मेमोरी आवंटन तेज़ रहता है।

\n

GC के काम को लॉग में देखा जा सकता है:

\n
GODEBUG=gctrace=1 go run main.go\n\ngc 1 @0.013s 4%: 0.031+0.42+0.017 ms clock, 0.25+0.10/0.42/0.0+0.13 ms cpu, 4->4->2 MB, 5 MB goal, 8 P\n
\n

यहाँ: 0.031+0.42+0.017 ms — STW + Mark + STW। 4->4->2 MB — mark से पहले, mark के बाद और sweep के बाद हीप का आकार।

\n\n

GC धीमा क्यों होता है: STW और पॉज़

\n

प्रदर्शन का सबसे बड़ा दुश्मन है STW (Stop The World)। हालाँकि Go पॉज़ को कम करने की कोशिश करता है, फिर भी ये होते हैं। खासकर अगर:

\n
    \n
  • आपके पास बहुत सारे पॉइंटर हैं (GC को सभी ऑब्जेक्ट्स को ट्रैवर्स करना होगा)
  • \n
  • हीप बड़ा है (अधिक ऑब्जेक्ट्स — अधिक समय marking में)
  • \n
  • आप बहुत अधिक कचरा पैदा कर रहे हैं (high allocation rate)
  • \n

ब्लॉग

पुस्तक अनुशंसाएँ