.NET 中的垃圾收集是否排除了驻留字符串?

Are interned strings excepted from garbage collection in .NET?

我正在努力减少进行 Gen2 收集所需的时间。我的应用程序创建并保存了大量字符串对象,这些对象在其生命周期中一直存在。

减少扫描对象的数量应该会减少 GC 时间。我想知道实习生池是否被排除在垃圾收集之外。反正那里也没什么可收集的。如果是这样,我可以实习所有这些字符串并加速 GC。

If you are trying to reduce the total amount of memory your application allocates, keep in mind that interning a string has two unwanted side effects. First, the memory allocated for interned String objects is not likely be released until the common language runtime (CLR) terminates. The reason is that the CLR's reference to the interned String object can persist after your application, or even your application domain, terminates. Second, to intern a string, you must first create the string. The memory used by the String object must still be allocated, even though the memory will eventually be garbage collected.

参考:https://msdn.microsoft.com/en-us/library/system.string.intern(v=vs.110).aspx

强调我的。

我做了一个快速测试,字符串的驻留似乎无法避免它们被 GC 扫描。至少在 .NET 4.5 64 位中不是。

class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 20000000; ++i)
        {
            string s = i.ToString("X");
            string.Intern(s);
        }
        GC.Collect(3, GCCollectionMode.Forced, true);
        long t1 = Stopwatch.GetTimestamp();
        GC.Collect(3, GCCollectionMode.Forced, true);
        long t2 = Stopwatch.GetTimestamp();
        Console.WriteLine((double)(t2 - t1) / Stopwatch.Frequency);
    }
}

此基准测试 returns 在 i5 3570k 上为 0.23 秒。如果将字符串放入数组而不是驻留,它 returns 0.26s。如果字符串是通过 (i % 10).ToString() 驻留和创建的,即有少量不同的实例,则基准 returns 微秒。

很遗憾,这不是绕过垃圾收集的方法。我认为 C# 应该有一些方法来将字符串标记为持久性并停止运行时在扫描它们时浪费时间。