6

可以说我有类似的东西:

public class Item
{
    public string Code;
    public List<string> Codes = new List<string>();
}

private void SomeMethod()
{
    List<Item> Items = new List<Item>();
    for (int i = 0; i < 10; i++)
    {
        Item NewItem = new Item();
        NewItem.Code = "Something " + i.ToString();
        NewItem.Codes.Add("Something " + i.ToString());
        Items.Add(Item);
    }

    //Do something with Items
}

我正在实例化 Item 而不是释放它,因为稍后我需要在列表中访问它(粗略示例)。

我想知道的是何时SomeMethod()完成执行,是否会取消引用项目(及其内容 - 包括 List<>)并允许垃圾收集器在运行时清理内存?基本上,这部分代码会导致任何内存泄漏,还是应该在SomeMethod()完成处理后取消引用所有内容。

我的理解是,当没有任何东西包含对对象的引用时,它将被垃圾收集,所以在我看来,这段代码应该没问题,但我只是想确保我理解正确。

编辑:

如果我要将其中一个对象添加Items到另一个仍在范围内的列表中(例如全局列表)。会发生什么?

4

5 回答 5

8

一旦你的变量Items超出范围,垃圾收集器确实会在闲暇时处理它(以及它的内容,因为你的代码是编写的)。

于 2012-12-13T15:56:47.230 回答
1

垃圾收集器将收集代码不再可以访问的任何内容。由于您将无法再访问您的项目列表或列表中包含的任何项目,因此垃圾收集器将在某个时候收集它们。您对垃圾收集器的理解是正确的。

于 2012-12-13T15:59:40.470 回答
1

行,

List<Item> Items

在方法的范围内声明。因此,当方法结束时,它超出了范围,并且列表被取消引用。

之后,当垃圾收集器认为合适时,内存将被释放。


顺便说一句,因为Items在“本地”范围内声明,我更愿意称它为items.

于 2012-12-13T16:03:32.773 回答
1

为了让事情保持理智并保持其工作,GC 必须承诺两件事:

  1. 垃圾会被收集。 这似乎很明显,但是如果 GC 不承诺在您不必告诉它的情况下清理托管对象,那它就毫无用处。

  2. 只会收集垃圾。 您不必担心 GC 会清理仍在使用的对象。

因此,一旦Items超出范围(即一旦函数返回),运行代码就无法再访问它,因此它可以被收集而无需您做任何事情。由于列表中的项目也不再可访问(它们的唯一链接在列表中),因此它们也符合条件。但是,如果您返回了对列表中某个条目的引用,则该对象仍在播放中并且还不能被收集。GC 会做正确的事。

事实上,GC几乎总是做正确的事。实际上,您只需要担心三种主要情况:

  • 如果您正在构建一个容器(例如,如果您正在制作自己的List类似作品)。就用户而言,容器中不再“存在”的任何对象通常应设置为 null,以便 GC 不会将它们视为可通过您的集合访问并错误地使它们保持活动状态。例如,如果您从集合中删除一个项目,则将引用清空或用另一个覆盖它。
  • 使用大 (>~85KB?) 对象。它们通常会停留在内存中,直到它们挤出其他所有内容,此时会运行完整的 GC 循环。(通常,在一个循环中只检查某些可能被丢弃的对象。完整的集合检查几乎所有内容,这需要更长的时间,但可能会释放更多的内存。)
  • 如果您使用的是 IDisposable 对象或本机/非托管资源。一些不称职的人不知道如何正确实现 IDisposable。如果你正在处理一个由这样一个无能者创建的库,那么你需要确保你的Dispose东西,或者只在一个using块内使用它,否则事情会变得非常奇怪。(如果你只使用 .net API,你是很安全的。但处置仍然是一种礼貌。)

对于几乎所有其他场合,GC 都可以正常工作。相信它。

于 2012-12-13T16:27:45.703 回答
1
  1. 方法中的所有变量都在一个堆栈帧中,所有这些变量将在方法执行后与堆栈帧一起被销毁。也就是说在 SomeMethod() 执行后,变量 Items 将不再存在,因此 new List() 将被标记为“可以收集”。

  2. 第二个问题是,有一个全局列表变量持有变量Items中的一个对象的引用,然后在SomeMethod()执行后,SomeMethod中的List将被标记为“可以收集”,并且全局列表变量引用的项目旁边的所有其他对象也将被标记为“可以收集”,原因是,列表实际上保存了指向堆中确切对象的引用所以共享对象不能由于被 globleList 引用的原因而被收集

于 2012-12-13T16:41:16.090 回答