想象一下这段代码:
int i=9999999;
while ( i > 1 )
{
string UnusedMemory="this is a string that eats some ram" + i.ToString();
i--;
}
如果仅在 GC.Collect()
运行时删除未引用的对象,则此代码应分配大量 ram,直到收集发生。但是它根本没有分配巨大的内存,为什么呢?是否在 IL 级别实现了某种“删除”?还是 GC.Collect()
自动调用得更快?我知道这是一个微不足道的例子,但如果它更复杂并且在该代码块中访问了字符串,它也不会吃掉很多 ram。
编辑:我更改了示例,使字符串始终是唯一的,因此它不能被“缓存”
最佳答案
字符串常量“缓存”在字符串池中,因此每次都是相同的字符串。
如果您对字符串使用方法 String.IsInterned
,那么它将返回 true
,这意味着它包含在池中。
来自 String.IsInterned :
The common language runtime automatically maintains a table, called the intern pool, which contains a single instance of each unique literal string constant declared in a program, as well as any unique instance of String you add programmatically.
The intern pool conserves string storage. If you assign a literal string constant to several variables, each variable is set to reference the same constant in the intern pool instead of referencing several different instances of String that have identical values.
此外,当需要内存或已分配足够的元素时,GC 会自动调用,因此即使未缓存字符串也不会成为问题。
来自 Fundamentals of Garbage Collection :
当以下条件之一为真时发生垃圾收集:
- 系统的物理内存不足。
- 托管堆上分配的对象使用的内存超过了可接受的阈值。这意味着已超过托管堆上可接受的内存使用阈值。该阈值会随着流程的运行不断调整。
- GC.Collect 方法被调用。几乎在所有情况下,您都不必调用此方法,因为垃圾收集器会连续运行。此方法主要用于特殊情况和测试。
是否可以更改或优化此行为? 是的,在某种程度上:Latency Modes
这个问题与以下内容密切相关: C# memory usage for creating objects in a for loop
关于c# - c#如何删除循环中分配的内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15849383/