c# مشكلات.NET Memory في تحميل ~ 40 صورة ، والذاكرة غير مستعادة ، يحتمل أن تكون بسبب تجزئة LOH




wpf memory-management (2)

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

في حالتك ، لا يمكنك التخلص من دفق الذاكرة حتى تنتهي من الصورة. عندما تريد إلغاء تحميلها ، قم بالالتفاف من خلال الصور وحاول التخلص من دفق الذاكرة.

https://code.i-harness.com

حسنا ، هذا هو أول غزوة في الذاكرة إنشاء ملف. NET (ضبط وحدة المعالجة المركزية قمت به) وأنا أضرب قليلا من الجدار هنا.

لديّ عرض في تطبيقي الذي يحمِّل 40 صورة (كحد أقصى) لكل صفحة ، كل منها يدير حوالي 3 ميغابايت. الحد الأقصى لعدد الصفحات هو 10. بالنظر إلى أنني لا أريد الاحتفاظ بـ 400 صورة أو 1.2 غيغابايت في الذاكرة دفعة واحدة ، أقوم بتعيين كل صورة إلى قيمة خالية عند تغيير الصفحة.

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

يلتصق الفئة الأصل SlideViewModelBase حول إلى الأبد في ذاكرة تخزين مؤقت ولكن يتم تعيين الخاصية MacroImage فارغة عندما يتم تغيير الصفحة. لا أرى أي مؤشر على أن هذه الأشياء يجب أن تبقى لفترة أطول من المتوقع.

بعد ذلك ، ألقيت نظرة على كومة الكائن الكبير واستخدام الذاكرة بشكل عام. بعد النظر في ثلاث صفحات من الصور لدي 691.9 ميغابايت من الذاكرة غير المدارة المخصصة و 442.3 ميجابايت على LOH. System.Byte[] ، الذي يأتي من بلدي System.Drawing.Bitmap لتحويل BitmapImage يأخذ إلى حد كبير كل مساحة LOH. هنا رمز التحويل الخاص بي:

public static BitmapSource ToBmpSrc( this Bitmap b )
{
    var bi = new BitmapImage();
    var ms = new MemoryStream();
    bi.CacheOption = BitmapCacheOption.OnLoad;
    b.Save( ms,  ImageFormat.Bmp );
    ms.Position = 0;
    bi.BeginInit();
    ms.Seek( 0, SeekOrigin.Begin );
    bi.StreamSource = ms;
    bi.EndInit();
    return bi;
}

أواجه صعوبة في العثور على كل تلك الذاكرة غير المدارة. كنت أظن أن كائنات System.Drawing.Bitmap في البداية ، ولكن ANTS لا تظهر لهم الالتصاق ، وأنا أيضا إجراء اختبار حيث تأكدت تماما أنه تم التخلص منها كلها وأنها لم تحدث فرقا. لذلك لم أفهم بعد أين تأتي كل تلك الذاكرة غير المدارة.

نظريتي الحالية هما:

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

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

إذا كنت بحاجة إلى مزيد من المعلومات أو ترغب في تجربة شيء آخر ، فيُرجى السؤال. عذرا عن النص هنا ، حاولت أن أبقيه موجزا قدر الإمكان.


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

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

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

وأي إصدار من .NET تستخدمه أيضًا؟ قبل إلى .NET 3.5 SP1 ، كانت هناك مشكلة معروفة حيث يمكن أن يسبب BitmapImage تسرب ذاكرة . كان الحل البديل استدعاء Freeze على BitmapImage.







memory-leaks