.NET:GC什么时候运行?内存泄漏?

Jos*_*nig 3 .net string memory-leaks immutability

我理解不变性是什么,以及String .NET类是如何特殊的.不变性使得它的行为类似于值类型,即使它是引用类型.得到它了.C#参考强调了这一点(参见字符串(C#参考),我强调的重点:

字符串是不可变的 - 在创建对象后,字符串对象的内容无法更改,尽管语法使其看起来好像可以执行此操作.例如,当您编写此代码时,编译器实际上会创建一个新的字符串对象来保存新的字符序列,并将该新对象分配给b.然后字符串"h"有资格进行垃圾回收.

作为一名自学成才的程序员,我不熟悉垃圾收集器和内存泄漏以及指针和内容.这就是我问这个问题的原因.C#编译器如何自动创建新的字符串对象并放弃旧的字符串对象的描述使得它看起来像一堆内存可能会被废弃的字符串内容用尽.许多对象都有处置方法或析构函数,因此即使是自动CLR垃圾收集器也知道何时以及如何在不再需要的对象之后进行清理.字符串没有这样的东西.我想看看如果创建一个程序实际上会发生什么,这样我就可以为自己和其他人说明创建并立即放弃字符串对象会占用大量内存.

这是程序:

class Program {
    static void Main(string[] args)
    {
        Console.ReadKey();
        int megaByte = (int)Math.Pow(1024, 2);
        string[] hog = new string[2048];
        char c;
        for (int i = 0; i < 2048; i++)
        {
            c = Convert.ToChar(i);
            Console.WriteLine("Generating iteration {0} (char = '{1}')", i, c);
            hog[i] = new string(c, megaByte);
            if ((i + 1) % 256 == 0) { 
                for (int j = (i - 255); j <= i; j++) { hog[j] = hog[i]; } }
            }
        Console.ReadKey();

        List<string> uniqueStrings = new List<string>();
        for (int i = 0; i < 2048; i++) {
            if (!uniqueStrings.Contains(hog[i])) { uniqueStrings.Add(hog[i]); }
        }
        Console.WriteLine("There are {0} unique strings in hog.", uniqueStrings.Count);
        Console.ReadKey();

        // Create a timer with an interval of 30 minutes 
        // (30 minutes * 60 seconds * 1000 milliseconds)
        System.Timers.Timer t = new System.Timers.Timer(30 * 60 * 1000);
        t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
        t.Start();
        Console.WriteLine("Waiting 30 minutes...");

        Console.ReadKey();
    }

    static void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        Console.WriteLine("Time's up. I'm collecting the garbage.");
        GC.Collect();
    }
}
Run Code Online (Sandbox Code Playgroud)

它创建了一系列独特的字符串,并且只在hog数组中有8个唯一的字符串.在我的测试中,该过程仍然保持在570 Mb到1.1 Gb(它变化).计时器部分等待30分钟,同时使进程保持活动状态(不休眠),在30分钟结束时,进程仍然保留所有额外的内存,直到我强行收集.这使得.NET垃圾收集器似乎错过了一些东西.很多其他地方的人都说调用GC.Collect()是可怕的.因此,内存似乎只是通过强制使用此方法的收集器来回收这一事实仍然使得它看起来像是错误的.

Cod*_*aos 8

你的帖子有点膨胀.简而言之,您在保留引用的同时分配了大量内存,然后注意即使在不再引用GC时GC也不会触发,即使经过很长时间也是如此.

这意味着GC不是基于时间触发的,而是基于发生的分配.一旦没有分配,它就不会运行.如果再次开始分配,内存最终会下降.

这与不变性或特别是字符串无关.