为啥清除对象的内容不会释放内存?

Posted

技术标签:

【中文标题】为啥清除对象的内容不会释放内存?【英文标题】:Why clearing the content of an object does not free memory?为什么清除对象的内容不会释放内存? 【发布时间】:2022-01-10 03:35:09 【问题描述】:

当我遇到以下情况时,我需要清理对象并立即释放其分配的内存时该怎么办?

在创建一个包含 1000 万字的 List<string> 后,进程内存增加到 ~150MB。

List<string> list = new();
int length = 10000000;
for (int i = 0; i < length; i++)

    list.Add("test");


Console.ReadLine();
list.Clear();
Console.ReadLine();

即使列表被清除,我也没有看到内存在此之后被释放。谁能给我一些指导,好吗?

【问题讨论】:

C# 只接受垃圾收集的建议。 显式地释放内存(不要在生产代码中这样做),你应该开始垃圾回收GC.Collect(2); 【参考方案1】:

您无法控制 C# 何时真正释放其内存。一旦你 Cleared 列出了所有曾经在其中的项目,就有资格被垃圾收集(假设没有其他东西可以引用它们,如给定的示例所示),但你无法控制何时正是 C# 的垃圾收集器实际上会释放它们。

【讨论】:

为什么需要它?您对内存有性能问题吗?内存是您应用程序的瓶颈?做你的代码,让 GC 自己做它的工作。想象一下你的清单是一个房间。你用人填满房间,然后人们离开。房间仍然存在,可供新人使用。你问“我怎样才能删除房间”。 “我需要在内存中保留几 GB” - 我相信有更好的方法来做你现在正在做的事情。也许你应该问“如何优化我当前的代码”并提供一个代码示例,所以 *** 房间里的聪明人会很乐意为你提供建议。 我的意思是,例如,您可以使用 FileStream+StreamReader 并保持内存正常,而不是使用 File.ReadAllText 加载整个 1GB 文件。 当需要内存时,垃圾收集器将决定释放或重用内存。垃圾收集是一项昂贵的操作,因此它会在可能的情况下运行并做它必须做的事情。你不应该担心这个。 @roccaforte 虽然我可以理解为什么你会认为它会,但是你可以看到List.Clear 的实现,看到它没有释放内部缓冲区,只是设置了所有值为 0。【参考方案2】:

List.Clear 只是用空值替换每个已清除字符串的所有引用副本。所以列表中的实际缓冲区大小完全相同,其中的值都是零。由于列表中只是充满了对文字池中单个字符串的引用,因此列表引用的所有对象都没有资格被收集(曾经在列表中的一个对象仍然存在,因为它在字符串实习生中池,它是有根的)。

要真正清除内部列表缓冲区,您要么需要删除对列表本身的所有引用,要么在列表上设置一个较小的 Capacity 以创建一个新的、较小的缓冲区,从而允许旧的缓冲区收集起来。

【讨论】:

知道了!谢谢! 1) 但是,如果我用随机小数列表代替单个字符串“测试”,会发生什么?我想不会有与您提到的“字符串实习生池”等效的东西来保存这些随机小数,对吧? 2) 如何删除对列表本身的所有引用? @roccaforte 然后您将一堆随机值更改为零,并且不会释放任何内存。对于任何其他类型的值类型也是如此。 Clear 导致任何释放内存的唯一方法是列表中是否存在无法从任何其他根引用访问的引用类型。在这种情况下,列表的缓冲区仍将保持根目录并使用大量内存,但所有引用对象的内存最终将能够被释放。在这种情况下,您的测试将在清除之前使用更多内存,然后在清除后使用相同的内存。 知道了!谢谢你。非常感谢。

以上是关于为啥清除对象的内容不会释放内存?的主要内容,如果未能解决你的问题,请参考以下文章

析构函数为啥能释放对象内存?

Java我可以主动去释放对象占的内存吗?可以的怎释放?

即使在所有对象都已被删除和清除后,我如何才能让 R 释放并停止持有内存?

C# 线程运行完之后自己会不会释放掉

安卓手机怎样释放内存?

C语言free释放内存后为啥指针里的值不变?竟然还可以输出