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

时间:2010-06-11 09:37:06

标签: c# .net memory

我写了这个小测试程序:

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();
        }
    }
}

发布版本中的输出是:

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

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

谢谢, 亚历

2 个答案:

答案 0 :(得分:9)

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

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

答案 1 :(得分:0)

确实我使用了私有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忽略了局部范围。