문제

F# Wikibook Under 돌연변이 상태를 캡슐화합니다 섹션, 다음 코드 스 니펫이 있습니다.

> 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 메모리 누출?
도움이 되었습니까?

해결책

'어휘 스코프'(이름이 프로그램 텍스트에 의미가있는 곳)와 '수명'(객체가 생성되고 파괴 된 시점 사이의 런타임 지속 시간)의 구별은 때때로 혼란 스러울 수 있습니다. 그러나이 예에 의해 입증 된 기술은 기능적 언어로 일반적입니다. 구현 세부 사항에 작은 어휘 범위를 제공하지만 (발신자의 구현 세부 사항을 숨 깁니다), 수명을 캡처하여 수명을 연장하여 수명이 수명이됩니다. Enclosing Object의 경우 -이 경우 'incc'함수). 이것은 기능적 프로그래밍에서 캡슐화를 수행하는 일반적인 방법입니다 (객체 지향 프로그래밍 클래스에서 공개/개인의 일반적인 캡슐화 기술과 대조).

이제이 특정 예에서는 'exc'가 최상위 함수 인 것처럼 보이며, 이는 프로그램의 수명에 대한 값이 지속되는 것을 의미합니다 (또는 fsi.exe에 입력하는 경우 대화식 세션). 이것을 '누출'이라고 부를 수 있지만 의도에 따라 다릅니다. 전체 프로그램의 전체 수명에 필요한 고유 한 ID 카운터가 있다면 해당 카운터 varable을 저장해야합니다. 어딘가에 그것은 전체 프로그램을 위해 지속됩니다. 따라서 이것은 'incr'가 어떻게 사용되는지에 따라 '누출'또는 'A에 의해 설계 기능'입니다 (나머지 프로그램 전체에 해당 기능을 사용해야합니까?). 어쨌든 여기서 핵심 요점은 'incc'가 메모리 리소스를 보유한다는 것입니다. 따라서 해당 리소스가 영원히 필요하지 않으면 더 이상 필요하지 않을 때 'incc'로 참조 된 폐쇄를 준비해야합니다. 일반적으로 이것은 다른 기능에 국한적으로 만드는 것일 수 있습니다.

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 폐쇄가 쓰레기를 수집하면 셀이 해방됩니다.

인크가 더 이상 도달 할 수 없을 때 카운터는 힙에서 제거됩니다. 쓰레기 수집으로 인해 메모리 누출이 아닙니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top