内存泄漏测试和常量变量

本文关键字:常量 变量 测试 泄漏 内存 | 更新日期: 2023-09-27 17:57:48

我正在进行检测类内存泄漏的测试。我使用以下模式进行此操作:

  • 在测试设置中获取初始内存(使用GC.GetTotalMemory(true)
  • 执行操作,例如对象的实例化
  • Dispose对象(通过useage块)
  • 在测试中获取内存(再次使用相同的方法,所有对象都超出了范围,因此应该进行垃圾收集)
  • 理想情况下,断言初始内存和结束内存之间的差异=0

在我的测试中使用内存分析工具,我看到const字符串(和相关的)声明被计入测试的泄漏内存中。我希望在进行初始内存测量时已经声明这些值,这样它们就不会产生测试检测到的"泄漏"。然而,我不想运行两次操作代码,因为这会阻止我检测静态变量中的变量泄漏(比如没有清理不应该有应用程序生存期的singleton模式对象)。

有办法做到这一点吗?我是否必须对每个测试用例的这些变量进行手动补偿(其缺点是必须积极维护,从长远来看可能不会发生)?运行时是否有一个时刻可以用于此目的?还是我只能接受我无法测试0字节附近的内存泄漏?

(对于那些感兴趣的人:我已经在使用WeakReferences和liveyness检查来监控我在测试中实例化的对象是否被正确地垃圾收集,但这不会涵盖泄漏的私有状态)

内存泄漏测试和常量变量

在托管内存中查找小内存泄漏或多或少是徒劳的。相反,如果可能的话,尝试一个更大的范围——分配对象100000次,看看在清理方面是否有显著的差异。

不过,在实践中,你可能想做一些完全不同的事情。内存量通常不是一个非常可靠的检查托管泄漏的方法。相反,您可能希望让应用程序在一个周期中反复运行,并使用例如CLRProfiler来查看对象的生存期。如果有什么可疑的东西持续了几分钟甚至几个小时,那很可能是泄漏。这给了你一个比检查内存大小更好的主意。

当然,总的来说,你不应该真的在乎。在真正伤害你之前,寻找内存泄漏几乎没有什么好处。请注意,我只是在谈论关于托管内存的。任何不使用托管内存的地方都应该引起高度重视,无论是本机代码、不安全指针还是任何其他形式的非托管句柄。请注意,这包括网络代码(套接字具有非托管内存)、文件操作(文件句柄)、一些同步原语(等待句柄)、图像数据(最著名的是GDI+的Bitmap类,WPF也充满了这些)等等。不过,一般来说,使用高级方法,您通常可以安全地忽略大多数问题,直到它们在现实条件下真正明显表现出来。

话虽如此,你的方法无论如何都是可疑的。您必须强制GC运行(使用当前的实现,它只会根据内存压力进行收集,而不是因为您离开了作用域——就GCing而言,堆栈是一个完全独立的问题)。强制完整GC的通常做法是这样的:

  1. GC.Collect()
  2. GC.WaitForPendingFinalizers()
  3. GC.Collect()

然后整个过程需要你先把所有东西都预热起来,也就是说,先做一个完整的测试周期。然后,如上所述执行完全强制GC。然后你做一千个循环的测试。然后,你再做一次完整的GC。这会让你对实际内存使用情况有一个更清晰的了解。

只有当静态字段内存泄漏使用大量内存时(在这种情况下,你应该简单地问为什么要使用这么多内存,我该怎么办?),或者如果它们随着多次调用或时间的推移而增加(在这种情况下,这种方法仍然可以让你发现问题),静态字段内存泄露才是有趣的。

另外,您的意思是,一个没有应用程序范围的单例对象是什么?如果这就是你所需要的,你真的,真的不应该使用singleton!您对单例的创建或销毁几乎没有控制权,并且在销毁后无法重新创建它。当然,大多数人可能会告诉你现在根本不要使用单身汉——其中一个原因是,除非他们没有状态,否则他们或多或少会扼杀使用单元测试等实践的机会。