我有一个班级:
Class Test
Friend myDict As Dictionary(Of Byte, Byte) = New Dictionary(Of Byte, Byte)
Friend Test1 As Boolean
Friend Test2 As Boolean
Friend Test3 As Boolean
Friend Test4 As Boolean
Friend Test5 As Byte
Friend Test6 As Byte
Friend Test7 As Byte
Friend Test8 As Boolean
Public Sub New(smt As String)
Test1 = True
Test2 = True
Test3 = True
Test4 = True
Test5 = 51
Test6 = 58
Test7 = 0
Test8 = True
' ADDING 64 DICTIONARY ENTRIES HERE
myDict.Add(11, 0)
myDict.Add(21, 0)
myDict.Add(31, 0)
myDict.Add(41, 0)
myDict.Add(51, 0)
myDict.Add(61, 0)
myDict.Add(71, 0)
myDict.Add(81, 0)
myDict.Add(12, 0)
myDict.Add(22, 0)
myDict.Add(32, 0)
myDict.Add(42, 0)
myDict.Add(52, 0)
myDict.Add(62, 0)
myDict.Add(72, 0)
myDict.Add(82, 0)
myDict.Add(13, Nothing)
myDict.Add(23, Nothing)
myDict.Add(33, Nothing)
myDict.Add(43, Nothing)
myDict.Add(53, Nothing)
myDict.Add(63, Nothing)
myDict.Add(73, Nothing)
myDict.Add(83, Nothing)
myDict.Add(14, Nothing)
myDict.Add(24, Nothing)
myDict.Add(34, Nothing)
myDict.Add(44, Nothing)
myDict.Add(54, Nothing)
myDict.Add(64, Nothing)
myDict.Add(74, Nothing)
myDict.Add(84, Nothing)
myDict.Add(15, Nothing)
myDict.Add(25, Nothing)
myDict.Add(35, Nothing)
myDict.Add(45, Nothing)
myDict.Add(55, Nothing)
myDict.Add(65, Nothing)
myDict.Add(75, Nothing)
myDict.Add(85, Nothing)
myDict.Add(16, Nothing)
myDict.Add(26, Nothing)
myDict.Add(36, Nothing)
myDict.Add(46, Nothing)
myDict.Add(56, Nothing)
myDict.Add(66, Nothing)
myDict.Add(76, Nothing)
myDict.Add(86, Nothing)
myDict.Add(17, 0)
myDict.Add(27, 0)
myDict.Add(37, 0)
myDict.Add(47, 0)
myDict.Add(57, 0)
myDict.Add(67, 0)
myDict.Add(77, 0)
myDict.Add(87, 0)
myDict.Add(18, 0)
myDict.Add(28, 0)
myDict.Add(38, 0)
myDict.Add(48, 0)
myDict.Add(58, 0)
myDict.Add(68, 0)
myDict.Add(78, 0)
myDict.Add(88, 0)
Console.WriteLine("Created New!")
End Sub
Public Sub New()
End Sub
End Class
当我使用以下方法克隆此类的1.000.000时:
Public Clones As List(Of Test) = New List(Of Test)
Public Sub BenchmarkTest(cnt As Long)
Clones.Clear()
GC.Collect()
Dim t As Long = Now.Ticks
Dim tst As Test = New Test("")
For x As Long = 1 To cnt
Clones.Add(DeepCopy(tst))
Next
Console.WriteLine("Copied " + Clones .Count.ToString + " in " + ((Now.Ticks - t) / 10000).ToString + "ms (" + ((Now.Ticks - t) / 10000000).ToString + " secs)")
End Sub
Public Function DeepCopy(inputTest As Test) As Test
Dim other As Test = New Test()
other.Test1 = inputTest.Test1
other.Test2 = inputTest.Test2
other.Test3 = inputTest.Test3
other.Test4 = inputTest.Test4
other.Test5 = inputTest.Test5
other.Test6 = inputTest.Test6
other.myDict = New Dictionary(Of Byte, Byte)(inputTest.myDict)
Return other
End Function
我打开任务管理器,看看我的应用程序使用了多少内存,我看到它使用1,300 + Mb
嗯,根据我的计算,我的班级大小只能是136个字节。 (64个字典条目(字节,字节)= 128bytes + 8bytes(对于test1到test8)= 136bytes)
将它与100万相乘应该是大约130M字节,而不是1300字节。
我的计算有什么问题?为什么它使用了近10倍的内存?
答案 0 :(得分:3)
你过度简化了计算。 .NET对象带来了必要的开销,不能简单地扁平化为逐字节等效。 (你的计算让我想起了C风格的结构对齐。)
Test类中内存的主要“抓取器”将是Dictionary。如果您逐步分析您的过程,您将看到简单地实例化一个空字典将消耗内存。当你开始添加项目时,事情变得更有趣。当您添加项目时,.NET集合不会以线性方式增长,这样效率太低。该集合将通过一些内部定义的方案(有时是斐波那契序列,有时是当前容量的简单加倍)增长,其中添加足够的项目将假设将添加另一个项目块并保留该内存。
我知道这是理论上的,抽象的,高级别的讨论,不会产生具体的答案,但我的意思是说这个问题非常复杂,对内存利用率进行精确计算可能非常困难。
这是一个不错的Code Project article,它提到了字典中性能和内存使用的一些问题。
这是another interesting link from Simple-Talk。评论部分包含有关.NET集合增长策略的有趣讨论。享受。
C#中的快速示例。 (这很脏,不要把它带到银行,但要证明这一点。See GC.GetTotalMemory)
Console.WriteLine("Bar is doing stuff.");
Console.WriteLine(GC.GetTotalMemory(true));
var dict = new Dictionary<byte, byte>();
Console.WriteLine(GC.GetTotalMemory(true));
dict.Add(8, 9);
Console.WriteLine(GC.GetTotalMemory(true));
输出:
53,328 53,980 54,052
请注意,空字节/字节字典占用652个字节。添加单个字节/字节条目会使字典大小增加72个字节...您没有看到的一件事是每个条目实际上都是由DictionaryEntry类的实例在内部表示的。