استراتيجيات لتعقب تسرب الذاكرة عندما تفعل كل شيء خاطئ

StackOverflow https://stackoverflow.com/questions/600757

  •  03-07-2019
  •  | 
  •  

سؤال

برنامجي، للأسف، به تسرب للذاكرة في مكان ما، لكني سأكون ملعونًا إذا عرفت ما هو.

وتتمثل مهمتها في قراءة مجموعة من الملفات تبلغ سعتها حوالي 2 ميجابايت، وإجراء بعض التحليل واستبدال السلسلة، ثم إخراجها بتنسيقات مختلفة.وبطبيعة الحال، هذا يعني الكثير من السلاسل، وبالتالي فإن تتبع الذاكرة يظهر أن لدي الكثير من السلاسل، وهو بالضبط ما كنت أتوقعه.هيكل البرنامج عبارة عن سلسلة من الفئات (كل منها في موضوع خاص بها، لأنني غبي) الذي يعمل على كائن يمثل كل ملف في الذاكرة.(يحتوي كل كائن على قائمة انتظار إدخال تستخدم قفلًا على كلا الطرفين.في حين أن هذا يعني أنه يمكنني تشغيل هذه المعالجة البسيطة بالتوازي، فهذا يعني أيضًا أن لدي عدة كائنات بحجم 2 ميجابايت موجودة في الذاكرة.) يتم تعريف بنية كل كائن بواسطة كائن مخطط.

تقوم فئات المعالجة الخاصة بي برفع الأحداث عندما تنتهي من معالجتها وتمرير مرجع إلى الكائن الكبير الذي يحمل جميع سلاسلي لإضافته إلى قائمة انتظار كائن المعالجة التالي.لا يؤدي استبدال الحدث باستدعاء دالة لإضافته إلى قائمة الانتظار إلى إيقاف التسرب.يتطلب أحد تنسيقات الإخراج مني استخدام كائن غير مُدار.لا يؤدي تطبيق Dispose() على الفصل إلى إيقاف التسرب.لقد استبدلت كافة المراجع إلى كائن المخطط باسم فهرس.لا النرد.ليس لدي أي فكرة عن سبب ذلك، وليس لدي أي فكرة عن المكان الذي يجب أن أبحث فيه.لا يساعد تتبع الذاكرة لأن كل ما أراه هو مجموعة من السلاسل التي يتم إنشاؤها، ولا أرى أين تلتصق المراجع في الذاكرة.

سنستسلم إلى حد كبير ونتراجع في هذه المرحلة، لكن لدي حاجة مرضية لمعرفة بالضبط كيف أفسدت هذا الأمر.أعلم أن Stack Overflow لا يمكنه تمشيط الكود الخاص بي، ولكن ما هي الاستراتيجيات التي يمكنك اقتراحها لتتبع هذا التسرب؟ربما سأفعل ذلك في وقتي الخاص، لذا فإن أي نهج قابل للتطبيق.

هل كانت مفيدة؟

المحلول

وأسلوب واحد سوف أحاول في الحد بشكل منهجي كمية رمز تحتاج إلى عرض المشكلة دون أن المشكلة تختفي. هذا هو المعروف بشكل غير رسمي باسم "فرق تسد" وهو أسلوب التصحيح القوية. وبمجرد الانتهاء من سبيل المثال <م> صغيرة الذي يوضح نفس المشكلة، سيكون من الأسهل بكثير بالنسبة لك لفهم. ولعل مشكلة الذاكرة سوف تصبح أكثر وضوحا في هذه النقطة.

نصائح أخرى

وهناك شخص واحد فقط يمكن أن تساعدك. اسم ذلك الشخص هو تيس Ferrandez . (صمت تكتم)

ولكن على محمل الجد. قراءة لها بلوق (المادة الأولى هي ذات الصلة إلى حد ما). سوف نرى كيف أنها تصحيحها هذه الأشياء تعطيك الكثير من نظرة عميقة إلى معرفة ما يحدث مع مشكلتك.

وأنا أحب CLR التعريف من Microsoft. ويوفر بعض أدوات عظيمة لتصور كومة المدارة وتعقب التسريبات.

وأنا استخدم dotTrace التعريف لتعقب تسرب الذاكرة. إنها أكثر بكثير من حتمية محاكمة المنهجية والخطأ، وحتى تتحول النتائج على نحو أسرع كثيرا.

لأي الإجراءات التي ينفذ النظام، وأنا أخذ لقطة ثم تشغيل بعض التكرار وظيفة، ثم تأخذ لقطة أخرى. والمقارنة بين اثنين تظهر لك كل الأشياء التي تم إنشاؤها في بين ولكن لم يطلق سراح. ثم يمكنك رؤية إطار مكدس عند نقطة خلقهم، وبالتالي العمل على ما لم يتم اطلاق سراح الحالات.

والحصول على هذا: http://www.red-gate.com/ المنتجات / ants_profiler / ملف index.htm

والذاكرة والتنميط الأداء مروعة. القدرة على رؤية الواقع الأرقام الصحيحة بدلا من التخمين يجعل الأمثل سريعة جدا. لقد استعملت لا بأس به في العمل للحد من أثر الذاكرة من التطبيق الرئيسي.

  1. أضف رمزًا إلى مُنشئ الكائن غير المصاب بتسجيله عندما يتم تحريكه ، وفرز معرفًا فريدًا.استخدم هذا المعرف الفريد عندما يتم تدمير الكائن مرة أخرى ، ويمكنك على الأقل معرفة أي منها ضل.
  2. GREP الرمز لكل مكان تقوم ببناء كائن جديد ؛اتبع مسار الرمز هذا لمعرفة ما إذا كان لديك تدمير مطابق.
  3. أضف مؤشرات التسلسل إلى الكائنات التي تم بناؤها ، بحيث يكون لديك رابط إلى الكائن الذي تم إنشاؤه قبل وبعد الولادة الحالية.ثم يمكنك مسحها لاحقًا.
  4. إضافة عدادات مرجعية.
  5. هل هناك "تصحيح malloc" متاح؟

ووتمكن التصحيح إضافة في SOS (وابن سترايك) غير poweful جدا لتعقب المدارة التسريبات 'الذاكرة لأنها، بحكم تعريفها اكتشافها من الجذور القيادة العامة.

وانها ستعمل في WinDbg أو استوديو البصرية (على الرغم من أنه في كثير من النواحي أسهل للاستخدام في WinDbg)

وانها ليست سهلة على الإطلاق للحصول على السيطرة مع. هنا هو تعليمي

وأود أن الثانية توصية للتحقق من بلوق تيس فرنانديز أيضا.

وكيف يمكنك أن تعرف عن حقيقة أن لديك بالفعل تسرب الذاكرة؟

وشيء آخر: لقد كتبت أن الطبقات معالجة الخاص بك تستخدم الأحداث. إذا كنت قد سجلت معالج حدث أنها سوف تبقي الكائن الذي يمتلك هذا الحدث على قيد الحياة - أي في GC لا يمكن جمعها. تأكد من إلغاء تسجيل جميع معالجات الأحداث إذا كنت تريد الأشياء الخاصة بك أن تكون القمامة التي تم جمعها.

كن حذرا كيفية تعريف "تسرب". "يستخدم المزيد من الذاكرة" أو حتى "يستخدم الكثير من الذاكرة" ليست هي نفسها كما "تسرب الذاكرة". هذا ينطبق بشكل خاص في بيئة جمع القمامة هذا. قد يكون الأمر ببساطة أن GC قد لا تكون هناك حاجة لجمع ذاكرة إضافية ترونه المستخدمة. تكون أيضا حذرا حول الفرق بين استخدام الذاكرة الظاهرية واستخدام الذاكرة الفعلية.

وأخيرا وليس عن "تسرب الذاكرة" سببها أنواع "الذاكرة" من القضايا. قيل لي مرة واحدة (وليس طلب) لإصلاح تسرب الذاكرة عاجل الذي كان يسبب IIS لإعادة بشكل متكرر. في الواقع، لم أكن التنميط وجدت كنت تستخدم الكثير من سلاسل من خلال فئة ب StringBuilder. I تنفيذ حمام سباحة كائن (من مقال MSDN) لStringBuilders، وذهب استخدام الذاكرة أسفل بشكل كبير.

وIIS لا يزال إعادة تشغيل كما في كثير من الأحيان. كان هذا بسبب عدم وجود تسرب للذاكرة. بدلا من ذلك، كان هناك التعليمات البرمجية غير المدارة التي ادعى أن يكون موضوع آمنة ولكن لم يكن. استخدامه في خدمة ويب (المواضيع متعددة) تسبب لكتابة جميع أنحاء كومة C مكتبة وقت التشغيل. لأن لا أحد كان يبحث عن استثناءات غير المدارة، لا أحد يرى هذا حتى حدث لي للقيام ببعض التنميط مع AQtime من الآلي QA. ويحدث أن يكون هناك نافذة الأحداث، التي وقعت لعرض صرخات الألم من مكتبة وقت التشغيل C.

وضعت الأقفال حول المكالمات إلى التعليمات البرمجية غير المدارة، و "تسرب الذاكرة" ذهب بعيدا.

إذا كائن غير مدار الخاص بك هو حقا سبب تسرب، قد ترغب في الحصول عليها استدعاء AddMemoryPressure عندما فإنه يخصص الذاكرة غير المدارة وRemoveMemoryPressure في Finalize / Dispose / أي وقت مضى حيث كان إلغاء تخصيص الذاكرة غير المدارة. وهذا يعطي GC على أفضل معالجة هذا الوضع، لأنه قد لا يدركون أن هناك حاجة لتحديد موعد جمع خلاف ذلك.

ولقد ذكرت بأن ما تتمتعون به باستخدام الأحداث. هل إزالة معالجات من تلك الأحداث عندما عمله الخاص بك مع وجوه الخاص بك؟ لقد وجدت أن "فضفاضة" معالجات الأحداث سوف يسبب الكثير من المشاكل تسرب الذاكرة إذا قمت بإضافة مجموعة من معالجات دون إزالتها عند عمله الخاص بك.

وأفضل أداة ملامح الذاكرة لصافي هو هذا:

http://memprofiler.com

وأيضا، بينما أنا هنا، وأفضل التعريف الأداء لصافي هو:

http://www.yourkit.com/dotnet/download/index.jsp

وكما أنها قيمة كبيرة مقابل المال، ويكون على ارتفاع منخفض وسهلة الاستخدام. يجب على أي شخص جاد في تنمية صافي النظر في كل من هذه الاستثمارات الشخصية وشراء على الفور. كلا منهم نسخة تجريبية مجانية.

وأعمل على محرك اللعبة في الوقت الحقيقي مع أكثر من 700K خطوط قانون مكتوب في C # و قد أنفقت مئات الساعات باستخدام كل من هذه الأدوات. ولقد استخدمت المنتج العلوم التقنية منذ عام 2002 وYourKit! على مدى السنوات الثلاث الماضية. على الرغم من أنني حاولت عدد غير قليل من الآخرين لقد عدت دائما لهذه.

وIMHO، وكلاهما رائعة تماما.

وعلى غرار شارلي مارتن، يمكنك أن تفعل شيئا من هذا القبيل:

static unigned __int64 _foo_id = 0;
foo::foo()
{
    ++_foo_id;
    if (_foo_id == MAGIC_BAD_ALLOC_ID)
        DebugBreak();
    std::werr << L"foo::foo @ " << _foo_id << std::endl;
}
foo::~foo()
{
    --_foo_id;
    std::werr << L"foo::~foo @ " << _foo_id << std::endl;
}

إذا يمكن إعادة إنشائها، ولو مرة واحدة أو مرتين مع نفس معرف تخصيص، وهذا سيتيح لك ننظر إلى ما يحدث الحق في ذلك الحين وهناك (من الواضح أن لابد من التعامل مع TLS / خيوط كذلك، إذا لزم الأمر، ولكن تركت ذلك لوضوح).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top