单元测试内存泄漏

Glu*_*uip 15 c# unit-testing memory-leaks

我有一个应用程序,其中存在大量内存泄漏.例如,如果打开一个视图并关闭它10次,我的内存消耗量会上升,因为视图没有被完全清理掉.这些是我的内存泄漏.从测试驱动的角度来看,我想写一个测试证明我的泄漏和(在我修复了泄漏之后)声明我修复了它.这样我的代码以后就不会被破解了.简而言之:

有没有办法断言我的代码没有从单元测试中泄漏内存?

我可以做这样的事情:

objectsThatShouldNotBeThereCount = MemAssertion.GetObjects<MyView>().Count;
Assert.AreEqual(0, objectsThatShouldNotBeThereCount);
Run Code Online (Sandbox Code Playgroud)

我对分析不感兴趣.我使用Ants profiler(我很喜欢),但也想编写测试以确保'泄漏'不会回来

我正在使用C#/ Nunit,但是对于有这个哲学的人来说,我很感兴趣...

Cum*_*yah 5

内存消耗的增加并不一定表示资源泄漏,因为垃圾回收是不确定的,可能尚未启动。即使您“放开”对象,只要CLR认为系统上有足够的资源可用,它们都可以保留它们。

如果您知道确实存在资源泄漏,则可以使用具有显式Close / Dispose作为其合同一部分(意为“使用...”构造)的对象。在这种情况下,如果您可以控制类型,则可以在对象的Dispose实现中标记对象的处置,以验证是否确实已经处置了这些对象,前提是您可以将生命周期管理泄漏到类型的界面中。

如果您选择后者,则可以对合同处理进行单元测试。在某些情况下,我使用与IDisposable等效的应用程序特定功能(扩展了该接口),添加了用于查询对象是否已处置的选项。如果您在类型上显式实现该接口,它将不会对接口造成太大的污染。

如果您无法控制所讨论的类型,则需要使用内存分析器(如在其他地方建议的那样)。(例如,Jetbrains的dotTrace。)


Jac*_*eja 5

当托管类型使用非托管资源而没有适当注意时,通常会导致内存泄漏。

一个典型的例子是System.Threading.Timer使用回调方法作为参数的。由于计时器最终使用的是非托管资源,因此引入了新的GC根目录,该根目录只能通过调用计时器的Dispose方法来释放。在这种情况下,您的类型也应该实现,IDisposable否则永远不能垃圾回收该对象(泄漏)。

您可以通过执行以下操作来为此场景编写单元测试:

var instance = new MyType();

// ...
// Use your instance in all the ways that
// may trigger creation of new GC roots
// ...

var weakRef = new WeakReference(instance);

instance.Dispose();
instance = null;

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Assert.IsFalse(weakRef.IsAlive);
Run Code Online (Sandbox Code Playgroud)


Lad*_*nka 1

您不需要单元测试,您需要内存分析器。您可以从CLR Profiler 开始。

  • 我已经在使用探查器,但想“固定”我的结果,以便为同一场景轻松创建新的泄漏 (8认同)