【问题标题】:Is it safe to use static Lists and LinkedLists?使用静态列表和链接列表是否安全?
【发布时间】:2012-10-16 21:06:12
【问题描述】:

如果“安全”是一个误导性的词,我很抱歉,我不确定在这种情况下该使用什么词。我想知道是否例如使用

 public static List<myObj> myList = new List<myObj>();

在 C# 中是可以接受的。无论如何,静态变量会在应用程序的整个生命周期中一直存在于 RAM 中,因此例如在 ASPX 等应用程序中,这可能会导致一些不需要的行为,并且 GC 不会收集分配。

我注意到,如果我有一个静态对象列表,比如静态“全局”类,即。

 globl.myList.add(foo);

然后它们会在应用程序的整个生命周期中保持不变。这是否意味着如果我有一个静态对象列表,那么附加到列表中的对象本身就是静态的,还是因为有对它们的引用,GC 不收集它们?换句话说,如果我删除了一个元素,GC 会在以后收集它还是会卡在堆中直到应用程序死亡?

提前谢谢!

【问题讨论】:

    标签: c# asp.net


    【解决方案1】:

    安全在这里是一个非常非常可疑的术语。在什么情况下安全?

    在记忆方面是否安全大部分是的。添加对static 列表的引用如果该引用后来被删除并且没有其他人引用它,则仍然可以收集,因此将项目添加到static 列表本身并不会阻止它被收集。

    现在,,如果该项目在所有引用消失之前被static列表持有很长时间,它可能会在GC生命周期中被提升到后面的世代,这可能释放所有引用后,使项目的内存清理速度变慢很多。

    在线程安全方面它安全吗:几乎没有。如果列表是可修改的,而其他线程可以读取它,那么您将需要同步对它的访问。也就是说,如果列表在创建时加载,多个线程可以安全地以“只读”方式访问它。

    而且,如果您确实需要并发访问可变集合,请考虑使用 .NET 4.0 中的并发集合 (MSDN)

    【讨论】:

    • 我不知道该用什么词,但我可以看到混乱来自哪里。不过你回答了我的问题。我想知道一旦从列表中取消链接,里面的元素是否会从堆中删除。
    • @SergueiFedorov:List&lt;T&gt; 本质上是一个 vector 或“动态数组”,如果你愿意的话。这意味着当您将项目添加到列表时,它将增加其内部内存以保存这些项目,如果您删除一个项目,它会将它们向下移动。但是,它通常不会在删除时重新分配较短的数组。不过,这通常不是问题。如果您真的想从列表中删除多余的容量,您可以在列表上调用TrimExcess(),它会将其大小调整为存储当前项目所需的容量。但请注意,这是一个 O(n) 操作。
    • 很高兴知道!出于某种原因,我一直认为 C# 中的列表是链接列表的实现,而不是向量。面试的好消息!
    • @SergueiFedorov:不,但 C# 确实有一个! System.Collections.Generic.LinkedList&lt;T&gt; - msdn.microsoft.com/en-us/library/he2s3bh7.aspx
    【解决方案2】:

    否定的。只要引用以这种方式保存,GC 就不会在您的列表中收集引用。

    对象本身并不是“静态的”——它们只是相对于静态引用而存在。

    【讨论】:

      【解决方案3】:

      只有列表是静态的。对象不是。如果您删除了一个对象并且没有对该内存的其他引用,那么它将成为垃圾收集的候选对象。

      【讨论】:

        【解决方案4】:

        在应用程序的整个生命周期中,静态变量始终存在于 RAM 中

        它们在 AppDomain 的生命周期内都在内存中 - 对于 IIS,这意味着 AppPool 的生命周期。 IIS 会定期回收 AppPools,因此无法保证数据会无限期地保留在内存中。

        这是否意味着如果我有一个静态的对象列表,那么附加到列表中的对象本身就是静态的,还是因为有对它们的引用,GC 不收集它们?

        不,对象不是静态的 - 因为存在对它们的引用,所以它们不会被收集。

        如果我删除了一个元素,GC 会在以后收集它还是会卡在堆中直到应用程序死掉?

        只要有东西引用它,就不会收集If。如果列表是唯一引用它,则一旦从列表中删除,它就有资格进行 GC。

        【讨论】:

          【解决方案5】:

          如果我删除一个元素,GC 会稍后收集它还是会 一直卡在堆中,直到应用程序死掉?

          您可以创建实验,您可以编写一个程序,加载像位图这样的大图像并将其添加到列表中,然后将其从列表中删除,然后启动 gc collect,您可以在任务管理器中看到(cntr+shift+ esc) 应用程序的内存消耗。例如:

          class Program
              {
                  public static List<Bitmap> Bitmaps = new List<Bitmap>(); 
          
                  static void Main(string[] args)
                  {
                      Bitmaps.Add((Bitmap) Image.FromFile(@"C:\\image.bmp")); // the size of image 23 mb (in that case), you will see in task manager that you app start consumes a lot of memory
                      Console.WriteLine("Memory state after loading image in list");
                      Console.ReadKey();
                      Bitmaps.RemoveAt(0);
                      GC.Collect();
                      Console.WriteLine("Memory after collect"); // and after deletion from list and start gc you will see that your app consume  less memory
                      Console.ReadKey();
                  }
              }
          

          这意味着GC从列表中删除后会收集你的元素。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-10-11
            • 1970-01-01
            • 2016-11-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多