【问题标题】:Static properties / methods memory allocation静态属性/方法内存分配
【发布时间】:2012-08-25 01:08:11
【问题描述】:

让我们举这个例子,我认为它涵盖了我所有的问题:

class SomeClass
{
    static SomeType PropertyA
    {
        get
        {
            if (....)
                return MethodA();
            else
                return MethodB();
        }
    }

    static SomeType MethodA() { ... }
    static SomeType MethodB() { ... }
}

调用 SomeClass.PropertyA 属性会造成内存泄漏吗?我的意见是不,因为属性本​​身没有支持字段,这会造成内存泄漏。我问这个是因为我读过静态属性会造成内存泄漏,但我认为它是负责内存泄漏的支持字段,因为它包含对实例的引用。

所以在上例中,上例中的 MethodA、MethodB 和 PropertyA 不应造成任何内存泄漏。我错了吗?

我的另一个问题是:我有很多类大多没有状态或数据。他们只是充当代理。其中一些方法被非常频繁地调用。我的问题是:我应该将这些类设为单例类、静态类还是常规类?

完美的例子是一个包含 5-10 个方法并执行一些 SQL 查询的类。

1) 如果我有它们作为常规,那么我需要经常创建它们(根据一些用户反应),调用一些方法,然后允许它们被垃圾收集。

2) 在单例和静态之间进行选择,优缺点是什么?

3) 如果我有一个包含代理方法的类,但有 2-3 个 IDbCommands,每个 IDbCommands 包含 10 个参数,并且有利于重用它们,那么在选择正确的模式时会改变什么吗?

编辑:由于我得到了一些让我更加困惑的答案,可能是由于误解,我将发布我的第一个问题的答案。我做了一个测试,我分配了一个大字节数组(300MB),它是通过PropertyA(和MethodA)检索的。 上例中的PropertyA abd MethodA 都不会持有对这个对象的引用,在获取它之后,一旦调用代码用数组完成,它就会被GC处理。因此,如果我们仅将静态属性与 getter 或静态方法一起使用,则不应存在任何内存泄漏。

【问题讨论】:

    标签: c#-4.0 static singleton


    【解决方案1】:

    所以在上例中,上例中的 MethodA、MethodB 和 PropertyA 不应造成任何内存泄漏。我错了吗?

    如果您的意思是它们不会创建或保留任何内存,那么这是真的 - 属性本身不会保留内存。

    静态字段不会造成“内存泄漏”——该类型的类型初始化程序将在第一次使用该类之前运行,并且,如果某个字段需要内存,则会为该字段分配内存。这个内存没有被清除——如果这就是你所说的“泄漏”——但是没有实例可以释放,所以这是预期和期望的行为。

    【讨论】:

    • 我已经更新了这个问题来解释我所说的内存泄漏是什么意思。当您说“如果某个字段需要内存,将分配该字段的内存”时,这是否意味着 SomeProperty 将不包含对 SomeClass 的引用(在我的第一个示例中)?
    • @Goran 是的,当然,如果“MethodA”或“MethodB”不返回 null。但是,是的,该字段将保存对实例的引用,这将防止引用被垃圾收集。
    • 所以,这是一个内存泄漏,这意味着我上面的代码是错误的代码,永远不应该使用。调用 PropertyA 每次都返回不同的实例。这意味着当调用代码完成使用 SomeClass 实例时,该实例将永远不会被收集(PropertyA 已引用它),但同时该对象不再可访问,因为对 PropertyA getter 的调用将返回对SomeClass 的新实例。
    • 同样适用于静态方法吗?在我的示例中是对 SomeType 实例的 3 次引用:调用代码、PropertyA 和 MethodA?
    【解决方案2】:

    简单的答案是一个问题:“这些方法做了什么,它们是否保持状态,除了简单的垃圾收集之外,它们是否需要清理?”

    如果他们不满足以上所有要求,那么按理说您不会有泄漏。仅当您不采取任何措施并且您不采取任何措施时,才会发生泄漏,您就没有泄漏。

    现在更多的是“内存压力”而不是泄漏。

    一般来说,我更喜欢实例方法,因为它提供垃圾收集并允许更轻松地模拟和测试场景。

    静态方法和变量与实例变量和方法存在相同的问题,因此泄漏(如果可能)适用于两者。

    【讨论】:

    • 这个问题本身就可以回答你的问题:它们只是代理方法,它们没有状态,也没有数据。这个(第二个)问题与内存泄漏无关,而仅与使用什么模式有关。所以,你的建议是让一切都像普通课程一样,并在每次需要时重新创建它们?单例类也准备好测试模拟(它是一个(单)实例类),那么为什么不把它作为单例呢?
    • 我想我的答案是这样的:如果你的整个属性和方法链没有状态(你说它们没有),那么是的,你没有内存泄漏。如果保持该链状态中的任何位置,并且该状态未被覆盖但在运行时调用时添加到该状态(例如,代码中的某些副作用不断将内容附加到静态列表,那么即使您有泄漏以上都是静态的)。
    猜你喜欢
    • 2011-12-02
    • 2023-03-10
    • 2016-01-26
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 2012-01-13
    • 2016-02-01
    • 1970-01-01
    相关资源
    最近更新 更多