当我的方法运行完毕时,垃圾收集器会释放这个列表吗

问题描述 投票:0回答:5

假设我有类似的东西:

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
将保留到仍在范围内的另一个列表中(例如全局列表)。会发生什么?

c# memory-management memory-leaks garbage-collection
5个回答
8
投票

一旦您的变量

Items
超出范围,垃圾收集器确实会在闲暇时收集它(及其内容,因为您的代码已编写)。


1
投票

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


1
投票

好的,

List<Item> Items

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

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


顺便说一句,由于

Items
是在“本地”范围内声明的,我更愿意将其称为
items


1
投票
  1. 方法中的所有变量都在一个栈帧中,并且在方法执行后所有这些变量将与栈帧一起被销毁。 也就是说,执行 SomeMethod() 后,变量 Items 将不再存在,因此 new List() 将被标记为“可以收集”。

  2. 第二个问题是,有一个全局列表变量保存了变量 Items 中的其中一个对象的引用,那么执行 SomeMethod() 后,SomeMethod 中的 List 就会被标记为“可以收集” ,并且除了由 globle 列表变量引用的项目之外的所有其他对象也将被标记为“可以收集” 原因是,列表实际上保存了指向堆中确切对象的引用 所以共享对象无法被收集,因为它被globleList引用了


1
投票

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

  1. 垃圾将被收集。这看起来很明显,但如果 GC 不承诺清理托管对象而无需你告诉它,那就毫无用处。

  2. ONLY垃圾将会被收集。你不必担心GC清理仍在运行的对象。

因此,一旦

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.