.Net中字符串(或任何其他对象)的内存使用情况

我写了这个小测试程序:

using System; namespace GCMemTest { class Program { static void Main(string[] args) { System.GC.Collect(); System.Diagnostics.Process pmCurrentProcess = System.Diagnostics.Process.GetCurrentProcess(); long startBytes = pmCurrentProcess.PrivateMemorySize64; double kbStart = (double)(startBytes) / 1024.0; System.Console.WriteLine("Currently using " + kbStart + "KB."); { int size = 2000000; string[] strings = new string[size]; for(int i = 0; i < size; i++) { strings[i] = "blabla" + i; } } System.GC.Collect(); pmCurrentProcess = System.Diagnostics.Process.GetCurrentProcess(); long endBytes = pmCurrentProcess.PrivateMemorySize64; double kbEnd = (double)(endBytes) / 1024.0; System.Console.WriteLine("Currently using " + kbEnd + "KB."); System.Console.WriteLine("Leaked " + (kbEnd - kbStart) + "KB."); System.Console.ReadKey(); } } } 

Release版本中的输出是:

 Currently using 18800KB. Currently using 118664KB. Leaked 99864KB. 

我假设GC.collect调用将删除已分配的字符串,因为它们超出范围,但它似乎没有。 我不明白也无法找到解释。 也许这里有人?

谢谢,Alex

您正在查看专用内存大小 – 托管堆将扩展以容纳字符串,但是当字符串被垃圾回收时,它不会将内存释放回操作系统。 相反,托管堆将更大,但有更多的可用空间 – 因此,如果您创建更多对象,则不需要堆扩展。

如果要查看托管堆中使用的内存,请查看GC.GetTotalMemory 。 请注意,由于垃圾收集的复杂性,所有这些都有一定程度的羊毛。

实际上我使用了私有mem大小,因为那是最接近Process Explorer的那个

如果我用这样的GC.GetTotalMemory重写程序:

 using System; namespace GCMemTest { class Program { static void Main(string[] args) { System.GC.Collect(); long startBytes = System.GC.GetTotalMemory(true); { string[] strings = new string[2000000]; for (int i = 0; i < 2000000; i++) { strings[i] = "blabla" + i; } strings = null; } System.GC.Collect(); long endBytes = System.GC.GetTotalMemory(true); double kbStart = (double)(startBytes) / 1024.0; double kbEnd = (double)(endBytes) / 1024.0; System.Console.WriteLine("Leaked " + (kbEnd - kbStart) + "KB."); System.Console.ReadKey(); } } } 

然后输出是:

泄露0KB。

只有我有'strings = null;' 这是这种情况,删除它,我泄漏100MB。 这意味着主例程中的本地作用域不会导致释放数组。 如果我将该部分移动到静态方法Test中,并调用该部分,我会泄漏几个字节。 我想我应该从中学到的是GC忽略了本地范围。