【问题标题】:C# class instance with static method vs static class memory usage具有静态方法的 C# 类实例与静态类内存使用情况
【发布时间】:2011-01-21 20:16:28
【问题描述】:

C# 或其他语言如何处理这两种情况之间的内存分配(和内存解除分配):

1.) 调用静态类的方法。

public Program {
    Foo foo = Loader.load();
}

public static Loader {
    public static Foo load() {
        return new Foo();
    }
}

2.) 在实例上调用方法,然后超出范围。

public Program {
    Foo foo = new Loader().load();
}

public Loader {
    public Foo load() {
        return new Foo();
    }
}

我想静态类已加载并保留在内存中;而类实例在 C# 闲暇时屈服于垃圾收集。这两种范式有什么优点或缺点吗?是否曾经有过一个永远不需要实例化的类(即某种资源加载器或工厂),但您仍然使用第二种方法来利用垃圾收集的情况?

我的问题的重要部分是,第一范式虽然在某些情况下在概念上是正确的,但是否可能会因不必要地保留记忆而受到影响。

【问题讨论】:

  • 第二个例子对我来说似乎不正确。调用静态方法需要一个以类名作为前缀的它。例如Loader.Load() & 不是 new Loader().Load()
  • 你说得对,Shah - 你不需要实例来调用静态方法。这有点意思:)
  • 啊,你们是对的,谢谢,我已经改写了它以了解我试图问的问题的实质。
  • 我认为他的意思是,拥有一个更大的静态类然后创建一个新实例并调用该实例的方法,然后让 GC 收集它的开销。
  • 简洁是智慧的灵魂,感谢5个字完美总结我的问题,哈哈。

标签: c# memory-management static-methods


【解决方案1】:

我找不到任何来源,但根据我的编程知识,当你引用一个类(非静态)时,它的结构被加载到内存中

创建一个类的实例只是为了调用一个方法,会浪费大量的处理能力(由于创建一个实例、为其分配内存和垃圾收集)。

而不是保留定义,然后在它之上,一个实例。为什么不保留定义(静态)。

只要您不在静态变量中存储任何数据,您的静态方法应该占用与您的非静态方法定义相同的内存量。但是使用静态方法,只有该方法将保存在内存中,并随时可以在需要时调用,而无需创建实例。而如果该方法是非静态的,则需要对其进行实例化(使用内存和处理能力)并收集垃圾(释放内存并使用 cpu),因此使用静态成员肯定更好。这就是他们的目的。

【讨论】:

  • 当第一次引用静态类时,我的理解是C#运行静态初始化器,将静态字段加载到内存中,并将Type数据(类结构)加载到内存中,并一直保持在那里程序运行时间。创建类的实例时,会处理构造函数,为实例字段分配内存,并将类型数据加载到内存中(如果还没有的话)。但是,当一个类的实例离开作用域时,它的数据最终会被遗赠给以太,但是 Type 数据是否曾经发布过?
【解决方案2】:

你的第二个例子不起作用,所以让我们探索一下真正的选择:

1.) 调用静态类的方法。

public Program {
   Foo foo = Loader.Load();
}

public static Loader {
   public static Foo Load() {
      return new Foo();
   }
}

2.) 调用非静态类中的静态方法。

public Program {
   Foo foo = Loader.Load();
}

public Loader {
   public static Foo Load() {
      return new Foo();
   }
}

3.) 在实例上调用实例方法

public Program {
   Foo foo = new Loader().Load();
}

public Loader {
   public Foo Load() {
      return new Foo();
   }
}

前两个是一样的。不管类是不是静态的,调用静态方法都是一样的。

第三个选项将在堆上创建一个类的实例。由于该类没有数据成员,因此它只有 16 个字节。它最终会被垃圾收集,但由于体积小,发生这种情况时并不重要。

调用实例方法也与静态方法略有不同。对类实例的引用随一起发送,您可以通过 this 关键字访问该引用。在这种情况下几乎没有什么区别,因为对象中没有要访问的真实数据。

【讨论】:

  • 当对象的实例被垃圾回收时,C# 程序的内存占用是否会发生变化(显然,除了实例字段数据之外),是否曾经卸载过类型信息?通俗地说,C# 是否会执行任何优化,例如“哦,这些类目前都没有实例,我不再需要它们,我将从程序中卸载原始 Type 数据并为自己节省一些内存”?
  • @jtb:不,据我所知,.NET 不会卸载曾经加载过的程序集。
  • @jtb GC 只有在没有引用/句柄等并且只有在操作系统内存资源稀缺时才会释放您的类占用的内存。
  • @TomasVoracek:是的,这是类的 instances 占用的内存。不收集类本身(代码 + 静态)。
【解决方案3】:

即使没有创建类的实例,也可以在类上调用静态方法、字段、属性或事件。

http://msdn.microsoft.com/en-us/library/79b3xss3(VS.80).aspx

因此,从这个意义上说,您的静态方法的行为就像您在类实例中使用它时一样:它的作用域是类型。

【讨论】:

  • 是的,对不起,我的例子写得不好,无法说明我的问题。我不知道这是否是正确的礼仪,因为你是对的,但我将不得不稍微改一下我的问题,以便提出我真正想问的问题。
  • 鉴于静态成员的作用域仅限于该类型,我认为内存使用不会因为您在该类型的实例中调用它而改变。
【解决方案4】:

第二种形式创建一个临时的Loader 对象(非常便宜)。无论您选择哪种方法,您都必须始终加载 Loader 类。

在这里获得的性能(节省内存)很少。如果在方法本地变量之外不需要“状态”,您通常会选择静态类中的静态成员。

【讨论】:

  • @Shah 它将编译。注意第二个例子不是调用静态方法!它在实例中调用普通的公共方法,然后将其作为垃圾收集,因为它不再被引用。
  • 是的,人们很困惑,因为我的原始帖子将第二个示例中的方法标记为静态,我对其进行了编辑。
猜你喜欢
  • 1970-01-01
  • 2011-01-17
  • 2012-04-19
  • 2011-11-10
  • 2012-11-12
  • 2013-02-10
  • 2014-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多