【问题标题】:How do I release the memory used by objects in my dictionary, or is that not needed?如何释放字典中对象使用的内存,还是不需要?
【发布时间】:2020-11-27 20:18:59
【问题描述】:

我创建了一个类(下面的简化版):

public class UsbDevice
{
    public UsbDevice()
    {
        Debug.WriteLine($"UsbDevice constructor called");
    }

    ~UsbDevice()
    {
        Debug.WriteLine($"UsbDevice destructor called");
    }
}

我使用字典来保存我所有 UsbDevices 的列表。

Dictionary<string, UsbDevice> _devices = new Dictionary<string, UsbDevice>();

UsbDevice usbDevice = new UsbDevice();
_devices.Add("Path of the device", usbDevice);

当我不再需要 UsbDevice 时,我将其从字典中删除。

_devices.Remove("Path of the device");

(为了简单起见,我省略了所有检查设备是否存在)

当我删除 UsbDevice 时,我看到没有调用析构函数。这仅在应用程序关闭时完成。所以这意味着 UsbDevice 对象仍然存在于内存中的某个地方,对吧?我知道 Dictionary 的“Remove”方法不会从内存中删除 UsbDevice,因为字典不知道 UsbDevice 是否可以在代码中的其他地方使用(引用)。

如何清除与 UsbDevice 相关的所有内存?如果我不摆脱那个内存,那么添加/删除周期会因为所有未使用的 UsbDevices 而增加内存使用量,对吧?我怎样才能避免这种情况?

【问题讨论】:

  • C# 不是那么基础:当调用终结器时
  • C# not 有析构函数。它借用了 C++ 的语法(不幸的是,因为它会引起不必要的混淆),但这些被称为终结器。区别很重要;绝大多数类不需要终结器,除了一些选择的围绕非托管资源的低级包装器(并且大多数这些类已经编写并且是框架的一部分)。如果需要对内存以外的内容进行确定性清理,其余所有用户都可以使用IDisposableusing
  • @knittl 谢谢!这确实有很大帮助!

标签: c# dictionary memory


【解决方案1】:
  1. 最好让 CLR 决定何时释放内存
  2. 如果您现在确实需要释放内存 - 您可以使用 GC.Collect();这种方式会消耗资源,所以不建议手动使用。
  3. ~UsbDevice() 不是析构函数。这是终结者。当垃圾收集器发现这个对象可以被移除时——它会检查它是否有一个终结器。如果不是 - 它只是删除对象。如果是 - 那么对象将被放入特殊队列中,其中所有对象都具有终结器。在某个时间点将调用终结器,但对象仍位于内存中。当 GC 进行另一次迭代时——它会看到有一个已经执行的终结器——对象可以从内存中删除。这就是为什么使用终结器不是一个好习惯的原因。
  4. 如果您想释放一些非托管资源并且您确切知道何时应该发生这种情况 - 请查看 IDisposable。

【讨论】:

  • 我使用 GC.Collect() 进行测试,然后看到我的终结器被调用(至少是那些从我的字典中删除的 UsbDevices)。所以我假设这表明如果 GC 决定需要一个集合,未使用的 UsbDevices 的内存将被释放。这绝对让我高枕无忧,我学到了很多东西!
  • 而且我确实不需要终结器——我只是用它们来检查何时释放内存。现在一切都清楚了!
猜你喜欢
  • 2010-09-24
  • 2015-09-05
  • 1970-01-01
  • 2012-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-04
  • 1970-01-01
相关资源
最近更新 更多