تخطَّ إلى المحتوى

runtime/pprof goroutineleak

اكتشاف goroutines متسرّبة للأبد runtime/pprof goroutineleak

ملف تعقّب goroutineleak بحزمة runtime/pprof (تجريبي منذ Go 1.26، جاهز للإنتاج منذ Go 1.27) يكتشف goroutines عالقة للأبد على قناة أو Mutex لن يتحرّر أبدًا — يعتمد على قابلية الوصول (reachability) لا مجرّد مهلة زمنية.

الـ goroutine «المتسرّبة» هي goroutine محجوزة (blocked) على أداة تزامن (قناة، sync.Mutex، sync.Cond...) لن تتحرّر أبدًا — لا خطأ يظهر، لا panic، فقط ذاكرة وموارد محجوزة للأبد تتراكم بصمت. اكتشاف هذا يدويًا صعب لأن البرنامج يستمر يعمل ظاهريًا بشكل طبيعي.

ملف تعقّب goroutineleak يستخدم تقنية مختلفة عن مجرّد قياس زمن الانتظار: يفحص عبر جامع القمامة (garbage collector) هل أداة التزامن التي تنتظرها goroutine ما زالت قابلة للوصول من أي goroutine قادرة على تشغيلها أو تحريرها — لو لا، فيستحيل منطقيًا أن تتحرّر تلك الـ goroutine مستقبلًا، فتُبلَّغ كمتسرّبة. هذا يكتشف فئة كبيرة من التسرّبات الحقيقية، لكن ليس كلها: تسرّبات عبر متغيّرات عامّة (package-level) أو متغيّرات محلية بـ goroutines ما زالت تعمل قد لا تُكتشَف لأن أداة التزامن تبقى قابلة للوصول نظريًا.

متاح كنوع profile اسمه goroutineleak بحزمة runtime/pprof، وأيضًا كمسار HTTP جاهز /debug/pprof/goroutineleak لأي خادم يستخدم net/http/pprof.

الصياغة

// عبر net/http/pprof (يسجّل المسارات تلقائيًا)
import _ "net/http/pprof"
// المسار الناتج: /debug/pprof/goroutineleak

// أو مباشرة عبر runtime/pprof
pprof.Lookup("goroutineleak").WriteTo(w, 0)

📄 مثال

package main

import (
  "log"
  "net/http"
  _ "net/http/pprof"   // يسجّل /debug/pprof/* تلقائيًا -- يشمل goroutineleak
)

func main() {
  // تصفّح لاحقًا: http://localhost:6060/debug/pprof/goroutineleak
  log.Fatal(http.ListenAndServe("localhost:6060", nil))
}

أهم النقاط

العنصرالوظيفة
goroutineleakاسم نوع الـ profile بحزمة runtime/pprof — جاهز للإنتاج منذ Go 1.27 (كان تجريبيًا بـ Go 1.26)
/debug/pprof/goroutineleakالمسار الجاهز عبر net/http/pprof لعرض التقرير من متصفّح أو أداة pprof
قيود الاكتشافيعتمد على قابلية الوصول (reachability) عبر GC — تسرّبات عبر متغيّرات عامّة قد لا تُكتشَف بنفس الدقّة

💡 نصائح عملية

  • فعّلها بالتطوير والاختبار المستمر (CI) لا فقط عند الشك بمشكلة فعلية — تصميمها لا يضيف كلفة أداء ملحوظة ما لم تُستخدَم فعليًا
  • لو خادمك أصلًا يسجّل net/http/pprof للأغراض المعتادة (CPU، memory)، goroutineleak متاح تلقائيًا بنفس المسار بلا إعداد إضافي

⚠️ أخطاء شائعة

  • الاعتماد عليها كضمان مطلق لعدم وجود أي goroutine متسرّبة — تكتشف فئة كبيرة من الحالات لكن ليس كل الحالات النظرية (خصوصًا عبر متغيّرات عامّة تبقى قابلة للوصول)
  • تسجيل net/http/pprof على خادم إنتاجي بمسار عام بلا حماية وصول — يكشف تفاصيل داخلية حسّاسة (بنية الذاكرة، الـ goroutines الجارية) لأي طرف يصل للمسار

🎓 تريد فهم الصورة الكاملة خطوة بخطوة؟ ابدأ من مسار GO الكامل بالعربي.