我们的应用程序突然启动了内存泄漏。我用以下测试代码(DotNet 3.5或4.5,visual studio 2013,windows 7/8 64位)成功复制了它:
一个大循环,创建一个包含一个数据表和一个数据列的数据集。 这是代码:
Imports System.Xml
Imports System.Xml.Serialization
Module Module1
Sub Main()
Dim x As XmlSerializer
x = New XmlSerializer(GetType(tClass)) ' needed for reproduce leak
Dim ds As DataSet
For i As Integer = 0 To 1000000
For j As Integer = 0 To 1000
ds = New DataSet
ds.Tables.Add("tb1").Columns.Add("dssd")
Next
Next
End Sub
End Module
Public Class tClass ' empty class
End Class
但我仍然不知道原因。
答案 0 :(得分:0)
在XmlSerializer
构造函数内创建的动态生成的运行时程序集正在使用内存。来自documentation:
动态生成的程序集
为了提高性能,XML序列化基础结构动态生成程序集以序列化和反序列化指定的类型。
这意味着,第一次时间为特定类型构造XmlSerializer
时,反射用于生成序列化和反序列化类型和所有引用类型的c#代码,然后将其链接并加载到内存中。您可以在TempAssembly
类中看到执行此操作的参考源代码。加载动态程序集会消耗内存,并且在卸载AppDomain
之前永远不会释放该内存。
但是,一旦生成,动态程序集将在以下情况下被运行时缓存并重用:
基础架构查找并重用这些程序集。仅当使用以下构造函数时才会出现此问题:
XmlSerializer.XmlSerializer(Type)
XmlSerializer.XmlSerializer(Type, String)
如果使用任何其他构造函数,则会生成同一程序集的多个版本,并且永远不会卸载,这会导致内存泄漏和性能下降。最简单的解决方案是使用前面提到的两个构造函数之一。否则,您必须将程序集缓存在Hashtable ...
中
由于 使用第一个构造函数,因此动态程序集 被缓存并重用,这意味着内存消耗是执行期间的一次性事件您序列化的每个根类型的应用程序 。只要您只序列化有限数量的类型,这些动态程序集使用的内存就会受到限制并且可以相当快速地稳定下来。
(如果您需要序列化可能无限数量的类型,因为您正在执行,比如dynamic class generation,那么您的内存使用量可能会不断增加。但我怀疑您是否正在这样做。)