【问题标题】:VB.NET Memory Size of Dictionary?VB.NET 字典的内存大小?
【发布时间】:2015-05-15 11:38:08
【问题描述】:

我有一堂课:

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 万应该是 130Mbytes,而不是 1300。

我的计算有什么问题?为什么它使用了将近 10 倍的内存?

【问题讨论】:

  • 你能用内存分析器代替任务管理器吗?任务管理器不可靠,见itwriting.com/dotnetmem.php
  • 好的,我使用 .NET 内存分析器完成了它,是的,它准确地显示了任务管理器所说的......

标签: .net vb.net performance memory dictionary


【解决方案1】:

您过度简化了计算。 .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 类的实例表示。

【讨论】:

  • 感谢您的回答。我知道 .NET 集合不会随着您添加项目而增长,但是(据我所知)当它达到最大值时,它会在内部加倍。所以我认为这里是;当我的字典最多达到 128 字节时,这里最糟糕的情况必须是 256 字节。但要大 10 倍?见鬼……也许我应该改用哈希表……
  • @RoniTovi:我添加了一个小的 C# sn-p 来显示 .NET 字典的增长。 (可以很容易地转换为 VB。)查看并使用信息。这将是令人大开眼界的。此外,哈希表在内存和性能方面可能更加昂贵。在此处查看有趣的讨论:stackoverflow.com/questions/301371/…
  • 很好的例子,谢谢。顺便说一句,我刚刚切换到 Hastables,现在它使用了 45 倍大的内存,性能很差(甚至可怜)!这令人惊讶。
  • @RoniTovi:.NET 可以充满惊喜!为了不让他们中的许多人措手不及,我强烈推荐 Jeffry Richter 通过 C# 编写的优秀 CLR:amazon.com/CLR-via-Edition-Developer-Reference/dp/0735667454 我认为这是我唯一一本从头到尾阅读的编程书籍,而且时间上的投资不断带来回报。跨度>
  • @Roni Tovi 哈希表会占用更多...它们是内存猪。
猜你喜欢
  • 2010-10-14
  • 2014-03-30
  • 1970-01-01
  • 2014-05-29
  • 2013-09-07
  • 1970-01-01
  • 2011-01-13
  • 2018-06-26
  • 1970-01-01
相关资源
最近更新 更多