自动检查
dotMemory 可以自动分析快照并检测多种内存问题。
字符串重复
重复创建具有相同值的字符串而不是重用现有字符串会浪费内存。 dotMemory 检测到重复的字符串并显示浪费了多少内存。
分析对象
点击检查标题中的链接或双击列表中的特定对象集。
修复问题
如果具有相同值的字符串浪费了大量内存或生成了显著的流量(例如,如果您的应用程序解析文本输入),请考虑实现 字符串驻留。
稀疏数组
稀疏数组是大部分填充零元素的数组。 从性能和内存使用的角度来看,稀疏数组效率低下。 dotMemory 会自动找到稀疏数组,并向您显示由于它们而丢失(被零值占用)的内存量。
分析稀疏数组
点击检查标题中的链接或双击列表中的特定对象。
可终结对象
可终结对象是使用 Finalize() 方法释放非托管资源的对象。 使用此模式的问题是,首先,可终结对象的生命周期至少会延长一个 GC 周期;其次,执行 Finalize() 方法的终结线程运行不可预测。 如果您希望尽快回收已释放的资源,这可能会导致问题,并可能导致性能突然下降。 dotMemory 检测并显示所有排队等待终结的对象以及 自上次快照以来已终结的对象。
分析可终结对象
修复问题
为导致问题的类型实现
IDisposable接口,并通过其Dispose()方法释放所有非托管资源。 有关释放模式的更多信息,请参阅 Microsoft Learn。
事件处理程序泄漏
当您将一个对象(称为监听器)订阅到另一个对象(称为源)的事件时,会发生此类泄漏。 例如: Timer1.Tick += OnTimer; 在订阅期间,源对象会获取对监听器对象事件处理程序的引用。 如果您删除了监听器,此引用将阻止其被垃圾回收。 dotMemory 会自动找到在事件处理程序中被引用但从未从相应事件中取消订阅的对象。
分析对象
点击检查标题中的链接或双击列表中的特定对象。
修复问题
当监听器不再需要时,请从事件中取消订阅。 例如:
Timer1.Tick -= OnTimer;
WPF 绑定泄漏
破坏 WPF 数据绑定模式也可能导致内存泄漏。 在您对源对象的某个属性执行数据绑定后,绑定目标对象会开始监听属性更改通知。 如果该属性不是 DependencyProperty 对象,并且目标对象未实现 INotifyPropertyChanged 接口,则源对象及其引用的每个对象可能会发生内存泄漏。 dotMemory 检测到此类绑定模式违规,并向您显示可能导致此类泄漏的对象列表。
分析对象
点击检查标题中的链接或双击列表中的特定对象。
修复问题
使源对象实现
INotifyPropertyChanged接口,或在不再需要时使用ClearBinding方法移除绑定。
WPF 集合绑定泄漏
此泄漏与上述 WPF 绑定泄漏类似。 如果绑定到的集合未实现 INotifyCollectionChanged 接口,WPF 会创建对此集合的强引用。 因此,它会在整个应用程序生命周期内保留在内存中。 dotMemory 检测并显示此类对象。
分析对象
点击检查标题中的链接或双击列表中的特定对象。
修复问题
使源集合实现
INotifyCollectionChanged接口。 另一种方法是使用ObservableCollection集合,因为它已经实现了INotifyCollectionChanged接口。
依赖项属性泄漏
此类泄漏的原因与事件处理程序泄漏相同。 垃圾回收器不会回收通过 AddValueChanged 方法订阅 DependencyProperty 更改的对象,直到使用 RemoveValueChanged 方法取消订阅。 dotMemory 检测并显示所有此类对象。
分析对象
点击检查标题中的链接或双击列表中的特定对象。
修复问题
当订阅对象的生命周期结束时,请使用
RemoveValueChanged方法取消订阅。
x:Name WPF 泄漏
此类泄漏是由于以下 WPF 特性导致的:WPF 会对在 XAML 中声明并使用 x:Name 指令的 UI 元素创建强全局引用。 例如:
因此,如果您动态移除以这种方式声明的元素,它仍会保留在内存中。
分析对象
点击检查标题中的链接或双击列表中的特定对象。
修复问题
一种移除泄漏的方法是改为在 C# 代码中声明 UI 元素,而不是在 XAML 中。 另一种方法是在您希望移除 UI 元素时调用父控件的
UnregisterName方法。 例如:this.UnregisterName("myControl1");