గోరౌటిన్ లీక్ అనేది ఎప్పుడూ ముగియని గోరౌటిన్ — ఇది బ్లాక్ చేయబడిందా లేదా ఎప్పటికీ నడుస్తుందా, మెమరీని వినియోగిస్తుంది (మరియు దాని సూచించిన వస్తువులను సజీవంగా ఉంచుతుంది) ప్రోగ్రామ్ యొక్క జీవితకాలం వరకు. గోరౌటిన్లను ప్రారంభించడం చేత విలువైనవి కాబట్టి, వాటిని లీక్ చేయడం సులభం, మరియు లీక్లు నిశ్శబ్దంగా సేకరమవుతాయి సేవ క్షీణించే వరకు లేదా మెమరీ ఖాళీ అయ్యే వరకు.
కారణం 1: ఛానెల్లో బ్లాక్ చేయబడింది పంపినవారు/గ్రహీత లేనిది
// ❌ LEAK — this goroutine blocks forever waiting to send
func leak() {
ch := make(chan int) // unbuffered
go func() {
ch <- 42 // blocks forever — NOBODY ever receives
}() // the goroutine is stuck, never exits
// function returns without reading ch → the goroutine leaks
}
ఛానెల్ పంపింపు/స్వీకరణపై బ్లాక్ చేయబడిన గోరౌటిన్ ఎప్పుడూ పూర్తి కాకపోతే ఎక్కువసేపు ఎదురుచూస్తుంది — ఇది కూడా సేకరించబడదు ఎందుకంటే ఇది సాంకేతికంగా ఇప్పటికీ "నడుస్తుంది."
కారణం 2: రద్దీకరణ / ముగింపు సంకేతం లేనిది
// ❌ LEAK — a goroutine in an infinite loop with no way to stop
func worker(jobs <-chan int) {
for {
job := <-jobs // blocks forever if jobs is never closed and stops sending
process(job)
} // no exit condition — leaks when no longer needed
}
నిరోధం 1: రద్దీకరణ కోసం context ఉపయోగించండి
// ✅ the goroutine can be told to stop
func worker(ctx context.Context, jobs <-chan int) {
for {
select {
case job := <-jobs:
process(job)
case <-ctx.Done(): // cancellation signal → exit cleanly
return // the goroutine terminates, no leak
}
}
}
// caller: ctx, cancel := context.WithCancel(...); defer cancel()
ప్రతి దీర్ఘకాలిక గోరౌటిన్కు రద్దీ చేయబడటానికి ఒక మార్గం ఇవ్వడం (<-ctx.Done()) ప్రాధమిక రక్షణ — ఇది గోరౌటిన్లు ముగిసిపోతుందని నిశ్చితం చేస్తుంది వారి పని ఇకపై అవసరం లేనప్పుడు.
నిరోధం 2: బఫర్ చేయబడిన ఛానెల్లు ఉపయోగించండి లేదా గ్రహీతలను నిశ్చితం చేయండి
// ✅ ensure a receiver exists, or use a buffered channel so the send doesn't block
ch := make(chan int, 1) // buffered → the send completes even if no one receives yet
go func() { ch <- 42 }() // doesn't block
నిరోధం 3: ఎప్పుడూ ఛానెల్లను మూసివేయండి / వాటిని సరిగా హరించండి
// ✅ close channels so range loops terminate
go func() {
defer close(results) // signal completion → for-range over results ends
for _, job := range jobs { results <- process(job) }
}()
లీక్లను గుర్తించడం
runtime.NumGoroutine() // monitor the goroutine count — steady growth = leak
import _ "net/http/pprof" // pprof exposes goroutine stacks (/debug/pprof/goroutine)
// the goleak library asserts no leaked goroutines in tests
runtime.NumGoroutine() పర్యవేక్షణ చేయడం (స్థిరంగా పెరుగుతున్న గణన లీక్ సూచిస్తుంది), pprof ద్వారా గోరౌటిన్ డంప్లను తనిఖీ చేయడం, మరియు పరీక్షలలో goleak ఉపయోగించడం ప్రధాన గుర్తింపు సాధనాలు.
ఇది ఎందుకు ముఖ్యమైనది
గోరౌటిన్ లీక్లు ఉత్పత్తి Go సేవలలో అత్యంత సాధారణ మరియు నిండిపోయిన సమస్యలలో ఒకటి.
గోరౌటిన్లను ప్రారంభించడం చాలా చిన్నది కాబట్టి, డెవలపర్లు వాటిని స్వేచ్ఛగా సృష్టిస్తారు — కానీ గోరౌటిన్ ఎక్కువసేపు బ్లాక్ చేయబడితే (ఛానెల్లో ప్రతిరూపం లేనిది, లేదా రద్దీకరణ లేని అనంత లూప్లో) ఎప్పుడూ ముగియదు మరియు దాని మెమరీని కూడా విడుదల చేయదు (దానిని సూచించే ప్రతిదీ సహా).
దీర్ఘకాలిక సర్వర్లో, ఈ లీక్లు నిశ్శబ్దంగా సేకరమవుతాయి, క్రమంగా సేవ క్షీణించే లేదా క్రాష్ అయ్యే వరకు మెమరీని వినియోగిస్తుంది — మరియు సూచించడం కష్టం ఎందుకంటే తక్షణ లోపం లేనిది.
కారణాలను (బ్లాక్ చేయబడిన ఛానెల్ కార్యకలాపాలు, గుపిత రద్దీకరణ) మరియు నిరోధకాలను (context-ఆధారిత రద్దీకరణ ప్రధాన రక్షణగా, సరైన ఛానెల్ మూసివేయడం, బఫర్ చేయబడిన ఛానెల్లు, గ్రహీతలను నిశ్చితం చేయడం) అర్థం చేసుకోవడం ఆధునిక సమకాలీన Go రాయడానికి అవసరం.
గుర్తింపు సాధనాలను ($runtime.NumGoroutine$, pprof, goleak) తెలుసుకోవడం సమానంగా ముఖ్యమైనది.
ఇది కీలక, తరచుగా-పరీక్షించిన విషయం ఇది డెవలపర్లను వేరు చేస్తుంది ఎవరు ఉత్పత్తి-స్థాయి సమకాలీన Go రాయగలరు వారి నుండి ఎవరు సేకరించిన కోడ్ రాయరు సుదీర్ఘ లోడ్ కింద.
