Я написал тестовую программу, в которой один Button
определен в XAML как содержимое Window
.При загрузке окна Button
программно заменяется как содержимое окна, и поле, ссылающееся на него, также заменяется, и другим Button
, который я создал программно.После этого я отслеживаю оба объекта Button
, используя слабые ссылки, и опрашиваю с интервалом 1/10 секунды свойство IsAlive
каждого из них.Перед первой проверкой IsAlive
при первом вызове метода опроса я также стираю корневые ссылки на программно определенный Button
.
Ожидание при запуске этого кода будет таким, несмотря наиз-за недетерминированности времени сборки мусора в C # оба объекта Button
в конечном итоге будут сообщаться как сборщики мусораХотя программно определенный Button
демонстрирует это поведение, обычно в течение 1/2 минуты, XAML Button
никогда не собирается.Я оставил запущенную программу более десяти минут, наблюдая это поведение.
Может кто-нибудь сказать мне, почему объект XAML Button
не собирается? В частности, я хотел бы знать, где ссылка на блокировку сборки мусора , находится ли она в моем коде или в реализации WPF.Возможно, это объект загрузки XAML.Я смотрю на какую-то утечку памяти?
Программа, описанная выше, включена ниже для справки.
MainWindow.xaml:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="300" Height="150" Loaded="Window_Loaded">
<Button Name="btn" />
</Window>
MainWindow.xaml.cs:
namespace Test {
public partial class MainWindow : System.Windows.Window {
private System.WeakReference wr_xamlBtn, wr_programmaticBtn;
public MainWindow() {
InitializeComponent();
}
private void Window_Loaded(object sender, System.Windows.RoutedEventArgs e) {
// Immediately upon the window's loading, create a weak reference to the
// button %btn defined in XAML.
wr_xamlBtn = new System.WeakReference(btn);
// Replace references in %btn and this.Content to the XAML button with
// references to a programmatically-defined button. This would be
// expected to free the XAML button for garbage collection.
btn = new System.Windows.Controls.Button();
Content = btn;
// Create a weak reference to the programmatically-defined button, so that
// when (strong) references to it are removed, it will be eligible for
// garbage collection.
wr_programmaticBtn = new System.WeakReference(btn);
// Provides a polling mechanism to see whether either the XAML button or
// the programmatically-defined button has been collected.
var dt = new System.Windows.Threading.DispatcherTimer();
dt.Tick += Poll;
dt.Interval = System.TimeSpan.FromMilliseconds(100);
dt.Start();
}
void Poll(object sender, System.EventArgs e) {
// If the programmatically-defined button hasn't had its references
// removed yet, this does so. This makes it eligible for garbage
// collection.
if (btn != null)
Content = btn = null;
// Uses the console to show a timestamp and the state of collection of the
// XAML button and the programmatically-defined button.
System.Console.WriteLine(
string.Format(
"XAML button {0}, Programmatically-defined button {1} @ {2}",
wr_xamlBtn.IsAlive ? "Alive" : "Collected",
wr_programmaticBtn.IsAlive ? "Alive" : "Collected",
System.DateTimeOffset.Now));
}
}
}
App.xaml:
<Application x:Class="Test.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml" />