【问题标题】:static variable = local temporary variable then return in c# - is this safe?静态变量 = 局部临时变量然后在 C# 中返回 - 这安全吗?
【发布时间】:2015-12-02 16:23:16
【问题描述】:

我是面向对象代码的新手,我想知道这段代码是否安全。 我有一个本地列表“TempCand”,它分配给该类的静态成员列表“候选人”。当我离开搜索方法时,我担心我的局部变量的内存会受到垃圾收集,这会影响我的静态变量。或者这样可以吗?

public class search
{
    class candidate
    {
        // ...
    }
    static List <candidate> Candidates = new List <candidate>();

    static public void clean_Candidates()
    {
        List <candidate> TempCand = new List <candidate>();
        // ...
        // copy some elements of Candidates in clean_Candidates()
        // ...
        Candidates = TempCand;
    }
}

【问题讨论】:

  • 从 GC 的角度来看,我没有看到问题,但从线程安全的角度来看,我确实看到了一个问题。您编写的代码看起来不是线程安全的。
  • @RonBeyer 这很可能是线程安全类的一部分,具体取决于使用Candidates 的其他方法如何工作。
  • 别担心了;你可以相信GC。它唯一的工作就是确保这些东西在需要的时候保持活力,并在以后被清理掉。
  • @JonHanna 它可能还有更多内容,但我们所能做的就是评论提供的代码,而不是推测没有提供的代码。正如其所写,没有看到“字里行间”是什么,它不是线程安全的。
  • 经验法则:如果有办法告诉您收集了特定对象,则不会收集该对象。所以,任何时候你说,“我担心 X 会被收集并导致问题 Y”,那么你可以放心 X 不会被收集,因为 Y 会让你注意到。反例大多只适用于非常先进的技术(例如,使用WeakReference 类)。我想也有人会争辩说终结器的集合是可观察的,但这几乎与 WeakReference 集合是可观察的一样明显(并且终结器是一种高级技术,imo)。

标签: c# variables static local assign


【解决方案1】:

我担心我的局部变量的内存受到垃圾回收的影响

其中一件事意味着某些东西不能被垃圾收集,那就是有一个正在使用的局部变量引用它。

这会影响我的静态变量

另一件事意味着某些东西不能被垃圾回收,那就是有一个引用它的静态字段。

局部变量本身根本不会受到垃圾回收的影响;在某些时候,当方法不使用它时(可能是在离开范围时,或者可能在此之前),本地内存可以重新用于其他用途。您几乎不会在意,因为如果您曾经使用它,那么根据定义,您不会处于永远不会使用它的地步(定时器和弱引用有一个例外,但您在这里都没有使用) .

现在,如果该局部变量是一个引用类型,那么它可能是保持被引用对象存活的东西。但是,这通常也不可见,因为只有当它是对该对象的 only 引用时。

当垃圾收集器启动时,它做的第一件事就是找到所有它不能收集的东西:

  1. 正在使用的局部变量中的任何内容。
  2. 静态字段中的任何内容。
  3. 以上两条规则规定的对象字段中的任何内容都不能被收集。
  4. 无法收集规则 3 中规定的字段中的任何内容,递归地应用此规则。

如果你能“看到”它,GC 就无法收集它。

GC 不会影响您的静态字段,因为根据定义,处于静态字段中是禁止使用的。

【讨论】:

    【解决方案2】:

    TempCand 和 Candidates 是对某些数据的引用(在这种情况下是 Candidate 对象的列表)。当然,您可以创建和销毁额外的引用而不影响对象。

    因此,一种可能的情况是:

    1. 您创建Candidates 列表并在其中放入5 个Candidate 对象。 由于对象被列表引用,而列表被静态属性引用,对象不会被垃圾回收。

    2. 您调用了CleanCandidates 静态方法。在其中,您创建另一个对候选人列表的引用 (tempCand)。您将对三个 Candidate 对象的引用添加到新列表中。

    3. 如果此时发生垃圾运行,则不会收集任何 Candidate 对象,因为它们仍然从静态列表中引用。

    4. 您设置静态Candidates 属性现在指向新列表并退出该方法。如果现在发生垃圾运行,它可以收集

      • Candidates 用来引用的旧列表。它现在没有被任何东西引用。
      • 旧列表中但不在新列表中的两个 Candidate 对象,因为现在没有任何引用它们。
      • tempCand 引用,因为它超出了范围 - 方法已完成,如果再次调用它将创建一个新引用。请注意,tempCand 引用的列表将不会被收集,因为它现在可以通过 Candidates 静态字段获得。 (请注意,本地字段的收集通常通过堆栈倒带“神奇地”完成)

    因此,您希望活着的候选人将会(并保持活着),而您丢弃的候选人最终将被垃圾收集(如果没有被其他一些未显示的代码引用)。


    也就是说,显示的代码不是线程安全的。您可能会执行两次CleanCandidates,并对集合造成严重破坏。您必须非常非常小心,因为您的静态列表实际上是共享应用程序状态。

    【讨论】:

      猜你喜欢
      • 2015-06-12
      • 2015-10-04
      • 1970-01-01
      • 1970-01-01
      • 2012-05-14
      • 2014-12-24
      • 1970-01-01
      • 2010-10-02
      相关资源
      最近更新 更多