gpt4 book ai didi

c# - 在C#中查找内存泄漏

转载 作者:可可西里 更新时间:2023-11-01 03:05:49 32 4
gpt4 key购买 nike

在以下程序中,尽管执行了垃圾回收,但未重新获得内存的初始大小。
1.内存的初始大小为
总内存:16,940字节
专用字节8134656

  • 在循环内创建的对象,以便在循环外完成gc收集时释放这些对象,因为这些对象没有范围。
  • 但是GC收集后的内存与初始大小不同
    总内存:29,476字节
    专用字节8540160
    句柄数:115

  • using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace MemoryLeakTest
    {

    class Program
    {
    static void DisplayMemory()
    {
    Console.WriteLine("Total memory: {0:###,###,###,##0} bytes", GC.GetTotalMemory(true));
    Console.WriteLine("Private bytes {0}", System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64);
    Console.WriteLine("Handle count: {0}", System.Diagnostics.Process.GetCurrentProcess().HandleCount);
    Console.WriteLine();
    }

    static void Main()
    {
    DisplayMemory();
    GC.Collect();
    for (int i = 0; i < 5; i++)
    {
    Console.WriteLine("--- New object #{0} ---", i + 1);

    object o = new object();

    GC.Collect();
    DisplayMemory();
    }
    Console.WriteLine("--- press any key to quit ---");
    Console.WriteLine();
    Console.Read();

    GC.Collect();
    DisplayMemory();
    }

    }
    }

    Output:
    =======
    Total memory: 16,940 bytes
    Private bytes 8134656
    Handle count: 115

    --- New object #1 ---
    Total memory: 25,588 bytes
    Private bytes 8540160
    Handle count: 115

    --- New object #2 ---
    Total memory: 25,576 bytes
    Private bytes 8540160
    Handle count: 115

    --- New object #3 ---
    Total memory: 25,576 bytes
    Private bytes 8540160
    Handle count: 115

    --- New object #4 ---
    Total memory: 25,576 bytes
    Private bytes 8540160
    Handle count: 115

    --- New object #5 ---
    Total memory: 25,576 bytes
    Private bytes 8540160
    Handle count: 115

    --- press any key to quit ---


    Total memory: 29,476 bytes
    Private bytes 8540160
    Handle count: 115

    *********************************

    专用字节和托管堆大小从其初始大小增加的原因是什么?

    最佳答案

    总体问题

    尝试计算和报告内存使用情况的方式所占用的内存是所测量的GC对象分配大小的10,000倍。

    此外,打印句柄计数不适用于手头的问题(因为在测试中没有打开/关闭句柄),但确实导致了显着的内存分配(仅删除该计数就将总分配减少了一半)。

    原始程序试图测量60-120字节对象的分配(取决于它是32位还是64位程序),但是它使用的函数导致每次调用时分配600 KB内存,一半其中在大型对象堆(LOH)上。

    提供了另一种测试方法,它表明在GC.Collect调用之后,所有对象确实都消失了。还提供了有关DisplayMemory功能的内存使用情况的详细信息。

    结论

    创建并收集10万个对象时,托管内存大小不会增加。当仅创建和收集5个对象时,该过程的专用字节增加了大约12 KB,但是SoS表明它不是来自托管堆。当您处理非常小的尺寸和对象数时,您将无法准确确定正在发生的事情。相反,我建议使用大量对象进行测试,这样很容易查看是否有泄漏。在这种情况下,没有泄漏,没有错,一切都很好。

    分析工具和方法

    我使用了两个工具来检查此程序的内存使用情况:

  • VS 2013 Pro-性能和诊断工具-我首先运行此程序,发现原始程序分配了3.6 MB的内存,而不仅仅是对象分配所期望的60-120字节。我知道字符串会使用一些内存并写入控制台,但是3.6 MB的内存令人震惊。
  • 罢工之子(SoS)-这是一个调试器扩展,可在Visual Studio和WinDbg中使用,并且与.Net Framework一起提供(请参阅计算机上每个框架版本目录中的sos.dll)。

  • VS 2013 Pro-性能和诊断工具-注释

    下面是在VS 2013 Pro的“性能和诊断工具”下通过将“分析方法”设置为“.NET内存分配”运行原始程序的结果。这提供了一个非常快速的线索,表明分配的内存超出了预期。请参阅图表上方的3.6 MB总分配。如果删除DisplayMemory调用,该调用将下降到2,476字节。

    罢工之子-笔记

    只要尚未在计算机上安装.Net 4.5,就可以在VS2010中使用SoS,或者可以在带有Update3的VS2012中使用它。只要确保在项目中启用非托管调试,并确保要启动32位进程,然后在VS调试器的“即时窗口”中运行“.load sos”即可。我用来查看此问题的命令是“!eeheap -gc”和“!dumpheap -stat”。

    替代测试程序
    class Program
    {
    static void Main()
    {
    // A few objects get released by the initial GC.Collect call - the count drops from 108 to 94 objects in one test
    GC.Collect();

    // Set a breakpoint here, run these two sos commands:
    // !eeheap -gc
    // !dumpheap -stat
    for (int i = 0; i < 100000; i++)
    {
    object o = new object();
    }

    // Set a breakpoint here, run these two sos commands before this line, then step over and run them again
    // !eeheap -gc
    // !dumpheap -stat
    GC.Collect();
    }
    }

    替代测试结果

    概括

    在分配并收集了100,000个System.Objects之后,最终得到的对象比开始时少4个,托管堆大小比开始时小900字节。

    垃圾收集按预期工作。

    基准-在第一次GC.Collect之后
    !eeheap -gc
    Number of GC Heaps: 1
    generation 0 starts at 0x024f23d0
    generation 1 starts at 0x024f100c
    generation 2 starts at 0x024f1000
    ephemeral segment allocation context: none
    segment begin allocated size
    024f0000 024f1000 024f23dc 0x13dc(5084)
    Large object heap starts at 0x034f1000
    segment begin allocated size
    034f0000 034f1000 034f5380 0x4380(17280)
    Total Size: Size: 0x575c (22364) bytes.
    ------------------------------
    GC Heap Size: Size: 0x575c (22364) bytes.

    !dumpheap -stat
    Statistics:
    MT Count TotalSize Class Name
    [...]
    6ed026b8 1 112 System.AppDomain
    6ed025b0 2 168 System.Threading.ThreadAbortException
    6ed05d3c 1 284 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
    6ed03a6c 2 380 System.Int32[]
    6ed0349c 20 560 System.RuntimeType
    0047fab8 14 1024 Free
    6ed02248 32 1692 System.String
    6ecefe88 6 17340 System.Object[]
    Total 95 objects

    在分配100,000个System.Objects之后,在最终GC.Collect之前
    !eeheap -gc
    Number of GC Heaps: 1
    generation 0 starts at 0x024f23d0
    generation 1 starts at 0x024f100c
    generation 2 starts at 0x024f1000
    ephemeral segment allocation context: none
    segment begin allocated size
    024f0000 024f1000 02617ff4 0x126ff4(1208308)
    Large object heap starts at 0x034f1000
    segment begin allocated size
    034f0000 034f1000 034f5380 0x4380(17280)
    Total Size: Size: 0x12b374 (1225588) bytes.
    ------------------------------
    GC Heap Size: Size: 0x12b374 (1225588) bytes.

    !dumpheap -stat
    Statistics:
    MT Count TotalSize Class Name
    [...]
    6ed024e4 1 84 System.OutOfMemoryException
    6ed02390 1 84 System.Exception
    6ed026b8 1 112 System.AppDomain
    6ed025b0 2 168 System.Threading.ThreadAbortException
    6ed05d3c 1 284 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
    6ed03a6c 2 380 System.Int32[]
    6ed0349c 20 560 System.RuntimeType
    0047fab8 14 1024 Free
    6ed02248 32 1692 System.String
    6ecefe88 6 17340 System.Object[]
    6ed025e8 100002 1200024 System.Object
    Total 100095 objects

    在最终GC.Collect之后
    !eeheap -gc
    Number of GC Heaps: 1
    generation 0 starts at 0x024f2048
    generation 1 starts at 0x024f2030
    generation 2 starts at 0x024f1000
    ephemeral segment allocation context: none
    segment begin allocated size
    024f0000 024f1000 024f2054 0x1054(4180)
    Large object heap starts at 0x034f1000
    segment begin allocated size
    034f0000 034f1000 034f5380 0x4380(17280)
    Total Size: Size: 0x53d4 (21460) bytes.
    ------------------------------
    GC Heap Size: Size: 0x53d4 (21460) bytes.

    !dumpheap -stat
    Statistics:
    MT Count TotalSize Class Name
    [...]
    6ed024e4 1 84 System.OutOfMemoryException
    6ed02390 1 84 System.Exception
    6ed026b8 1 112 System.AppDomain
    0047fab8 9 118 Free
    6ed025b0 2 168 System.Threading.ThreadAbortException
    6ed05d3c 1 284 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
    6ed03a6c 2 380 System.Int32[]
    6ed0349c 20 560 System.RuntimeType
    6ed02248 32 1692 System.String
    6ecefe88 6 17340 System.Object[]
    Total 91 objects

    审查DisplayMemory函数的内存使用情况

    与System.Object分配相比,DisplayMemory是一个内存消耗。它正在创建字符串(在堆上),它调用来获取内存的函数本身使用了大量的内存(大约600 KB)。

    调用DisplayMemory之前的内存使用情况
    !eeheap -gc
    Number of GC Heaps: 1
    generation 0 starts at 0x02321018
    generation 1 starts at 0x0232100c
    generation 2 starts at 0x02321000
    ephemeral segment allocation context: none
    segment begin allocated size
    02320000 02321000 02323ff4 0x2ff4(12276)
    Large object heap starts at 0x03321000
    segment begin allocated size
    03320000 03321000 03325380 0x4380(17280)
    Total Size: Size: 0x7374 (29556) bytes.
    ------------------------------
    GC Heap Size: Size: 0x7374 (29556) bytes.

    !dumpheap -stat
    Statistics:
    MT Count TotalSize Class Name
    [...]
    6ed05d3c 3 468 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
    6ed0349c 20 560 System.RuntimeType
    6ed02248 38 2422 System.String
    6ecefe88 6 17340 System.Object[]
    Total 102 objects

    调用DisplayMemory后的内存使用情况
    !eeheap -gc
    Number of GC Heaps: 1
    generation 0 starts at 0x023224fc
    generation 1 starts at 0x023224f0
    generation 2 starts at 0x02321000
    ephemeral segment allocation context: none
    segment begin allocated size
    02320000 02321000 02371ff4 0x50ff4(331764)
    Large object heap starts at 0x03321000
    segment begin allocated size
    03320000 03321000 033653c0 0x443c0(279488)
    Total Size: Size: 0x953b4 (611252) bytes.
    ------------------------------
    GC Heap Size: Size: 0x953b4 (611252) bytes.

    !dumpheap -stat
    Statistics:
    MT Count TotalSize Class Name
    [...]
    6ed02c08 9 954 System.Char[]
    006dfac0 17 1090 Free
    6ed03aa4 156 1872 System.Int32
    6ecffc20 152 3648 System.Collections.ArrayList
    6ed05ed4 9 7776 System.Collections.Hashtable+bucket[]
    7066e388 152 16416 System.Diagnostics.ProcessInfo
    6ed02248 669 20748 System.String
    706723e4 152 29184 System.Diagnostics.NtProcessInfoHelper+SystemProcessInformation
    6ecefe88 463 48472 System.Object[]
    706743a4 2104 75744 System.Diagnostics.ThreadInfo
    70666568 2104 151488 System.Diagnostics.NtProcessInfoHelper+SystemThreadInformation
    6ed0d640 2 262168 System.Int64[]
    Total 6132 objects

    关于c# - 在C#中查找内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18739892/

    32 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com