在F#维基教科书下 封装状态变化 部分,有下列代码段。

> let incr =
    let counter = ref 0
    fun () ->
        counter := !counter + 1
        !counter;;

val incr : (unit -> int)

> incr();;
val it : int = 1

> incr();;
val it : int = 2

> incr();;
val it : int = 3

第一,它似乎很容易吞下事实,即,变 counter 值的增量; incr 被援引。

但经过思考这一段时间,我不明白的时候 counter 脱离堆,以及如何 counter 仍然指的是以前值前正在增加。如何 counter 生活在 incr 功能范围的生存,通过多功能的电话?

所以,主要问题是:

  • 什么时候 counter 脱离堆?
  • 是不是 counter 存储器泄漏?
有帮助吗?

解决方案

之间的区别'的词汇范围'(其中一名具有的意义文本的程序)和'生'(runtime之间的持续时间时,目的是创建和销毁)有时可能会造成混乱,因为往往这两个高度相关。然而对技术证明的这一实例是共同的功能语言:你给一个执行情况的详细小的词汇范围(隐藏的执行情况的详细信息,从呼叫者),但延长其使用寿命通过捕获它在一个封闭(使其终身成为终身的封闭对象在该实例中的'incr'功能)。这是一个共同的方法来做到封装在编程功能(比通常封装的技术的公共/私人类在面向对象编程)。

现在,在这个特定例子,它看起来像'incr'是一个顶级的功能,这意味着它的价值持续的使用寿命程序(或互动的会议,如果输入的fsi.exe).你可以叫这个'泄露,但这取决于意图。如果你有一些独特的id计数器你需要的整个生命周期的整个程序,如果答案是肯定的,那么你将有储存,反varable 某个地方 它持续的时间为整个程序。因此,无论这是一个泄漏的"或"一个设计特征的'取决于如何'incr'将被用(将需要使用该功能对于整个休息的程序?).在任何情况下,关键的一点是,'incr'持有的存储器资源,所以,如果你不需要这些资源的永远,你应该安排对于封闭所引用的'incr',成为无法访问时这是不再需要。通常,这可能是通过使它地方的其他一些功能,例如

let MyComplicatedFuncThatNeedsALocalCounter args =
    let incr = 
        // as before
    // other code that uses incr
    // return some result that does not capture incr

其他提示

在这种情况下, incr 是一个顶级的功能(实现为一个静态的领域,如果我没有记错的话.) 它拥有一个封闭,这又有一个参考,ref电池命名的 counter.只要存在这种封闭的, ref 细胞是保持在存储器中。

现在这个顶级的结合将实际上永远不会得到垃圾收集,因为它是一个静态的只读领域。(C#而言)。如果你的,但是,有封锁,像这一个 生(开本地或在一个对象), ref 细胞将会被释放时关闭垃圾收集。

反脱离堆当incr不再是访问。这不是一个存储器泄漏因收集垃圾。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top