سؤال

تحديث: جربت هذا على آلة أخرى ، مثبتة بشكل أكثر نظافة ،. لم أستطع إعادة إنتاج هذا على هذا الجهاز. إذا اكتشفت المكون المخالف (vsstudio) الذي يتسبب في ذلك ، فسوف أخبرك بذلك.

أقوم بإنشاء بعض uielements من الكود خلفها وكنت أتوقع مجموعة القمامة لتوضيح الأشياء. ومع ذلك ، فإن الكائنات ليست حرة في الوقت الذي كنت أتوقعه فيه. كنت أتوقع أن يتم تحريرهم في removeeat (0) ، لكن يتم إطلاق سراحهم فقط في نهاية البرنامج.

كيف يمكنني تحرير الأشياء عند إزالتها من مجموعة الأطفال من القماش؟

<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
    MouseDown="Window_MouseDown">
  <Grid>
    <Canvas x:Name="main" />
  </Grid>
</Window>

الرمز وراء:

public partial class MainWindow : Window
{
  public MainWindow()
  {
    InitializeComponent();
  }

private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
  GC.Collect(); // This should pick up the control removed at a previous MouseDown
  GC.WaitForPendingFinalizers(); // Doesn't help either

  if (main.Children.Count == 0)
    main.Children.Add(new MyControl() { Background = Brushes.Yellow, Width = 100, Height = 50 });
  else
    main.Children.RemoveAt(0);
 }
}

public class MyControl : UserControl
{
  ~MyControl()
  {
    Debug.WriteLine("Goodbye");
  }
}

لا يوجد حل صحيح

نصائح أخرى

يتغيرون

public class MyControl : UserControl

ل

public class MyControl : ContentControl

وسيقول وداعًا (بعد المرة الثانية التي تقوم فيها بإزالة عنصر التحكم.) لقد تحقق أيضًا من أن الذاكرة لا تتسرب باستخدام

Debug.WriteLine("mem: " + GC.GetTotalMemory(true).ToString());

انظر أيضا هذه:

يمكنك إزالة testControl عن طريق إزالة الشبكة. هناك العديد من العمليات غير المتزامنة عليها معلقة ، ولا يمكن أن تكون GC'D حتى تكتمل تلك العمليات (وتشمل تلك رفع الحدث الذي تم تحميله وبعض رمز التنظيف في محرك التقديم).

لقد تحقق من أنه إذا انتظرت حتى تكتمل هذه العمليات (على سبيل المثال جدولة عملية مرسل في أولوية ContextIdle) ، يصبح TestControl مؤهلاً للحصول على GC ، بغض النظر عن وجود ارتباط على TextBlock.

يجب أن يكون لدى UserControl حدث داخلي لا ينظف بسرعة ، أو قد يكون خطأ مع VS2010 RC. سأبلغ عن ذلك من خلال Connect ، ولكن الآن قم بالتبديل إلى ContentControl.

نظرًا لأنك تستخدم UserControl ، أفترض أنه عليك أيضًا التبديل إلى استخدام قالب generic.xaml. هذا ليس صعبًا للغاية في التغيير (وبالنسبة لمعظم الأشياء هو حل أفضل.)

الكائنات في C# ليست "تحرير" تلقائيًا بمجرد استخدامها.

بدلاً من ذلك ، عند إزالة الكائن من جهاز التحكم الخاص بك ، يصبح مؤهل لجمع القمامة في هذه المرحلة ، على افتراض أنه ليس لديك أي إشارات أخرى إلى ذلك uilement.

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

فقط ثق في أنه سيتم تنظيفه في النهاية. هذا هو جمال C# (و .NET بشكل عام) - تتم معالجة الإدارة والقلق من هذا لك.


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

this.UpdateLayout();

بعد إزالة العنصر (العناصر) من أطفال قماش. سيؤدي ذلك إلى توفر الكائنات لـ GC.

هناك 3 أجيال من جمع القمامة في C#، لذلك حتى لو لم تكن هناك إشارات إلى كائناتك ، فقد يستغرق الأمر 3 مجموعات من القمامة لتحريرها.

يمكنك استخدام المعلمة GC.Collect () لإجبار مجموعة القمامة من الجيل الثالث ،
ومع ذلك ، فإن أفضل موافقة هو عدم الاتصال بـ gc.collect () بنفسك ،
بدلاً من ذلك ، استخدم واجهة Idisposable وقم بربط الأطفال بـ ObservableCollection وعندما تحصل على حدث تم تجميعه () من أي كائنات تمت إزالتها.

قد تجد هذا من الاهتمام. لقد اكتشفت مؤخرًا أن X: Name Markup Extension يخزن إشارة إلى UiElement في عنصر التحكم الأصل في قاموس مفتاح باسم السلسلة.

عندما تقوم بإزالة uielement من والديه ، يحتفظ القاموس بالإشارة إلى عنصر التحكم.

هناك منشور مدونة / فيديو تصحيح تسرب الذاكرة هنا: WPF X: اسم تسرب الذاكرة

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

تحديث: أنت تقوم بإلغاء تسجيل فئة مسماة باستخدام Namescope

this.grid.Children.Remove(child); // Remove the child from visual tree
NameScope.GetNameScope(this).UnregisterName("child"); // remove the keyed name
this.child = null; // null the field

// Finally it is free to be collected! 

كان لدينا نفس المشكلة واعتقدنا أيضًا أن هذا قد يكون السبب. لكننا قمنا بتحليل مشروعنا باستخدام أدوات Profiler للذاكرة ووجدنا أنه لا يوجد شيء يتعلق بالشبكة. لذلك أعتقد أن اقتراحي هو مجرد إلقاء نظرة على مشروعك على أداة Memory Profiler وشاهد ما يحدث داخل مشروعك. آمل أن يساعد هذا.

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