2017-12-29 48 views
1

FFI를 통해 일부 데이터를 할당하고 파이널 라이저를 연결할 때 하스켈에 ForeignPtr이 표시됩니다. 이 포인터가 참조 해제되면 GC는 포인터를 수집하여 종료자를 실행합니다. 그러나 수집은 GC가 실행될 때만 발생하며 "참조 해제"는 GC를 강제 실행하지 않습니다. 나는. 많은 포인터가있을 수 있지만 포인터 자체는 많은 메모리를 차지하지 않으므로 RTS는 외부 데이터의 크기가 RTS에 의해 추적되지 않기 때문에 GC를 시작하는 이유를 알지 못합니다 (investigations). 이 올바른지?외국 데이터 및 가비지 수집

"이 포인터가 참조 해제되면 즉시 수집합니까?"RTS에 어떻게 통신합니까? GC 시작시기를 제어 할 수있는 플래그가 있습니까? 실제 프로그램에서 문제가 되는가? (실제 프로그램에는 항상 GC를 자극 할 정도의 충분한 가비지가 있음)?

+1

[이 블로그 게시물] (http://www.tweag.io/posts/2017-11-29-linear-jvm.html)에서는이 문제에 대해 설명합니다. 그것은 이런 종류의 일에 대한 예술의 현재 상태에 대한 좋은 요약입니다. – Alec

답변

3

RTS는 GC를 실행할 때까지 어떤 데이터도 참조되지 않는지 전혀 알지 못합니다. GHC에는 참조 카운팅 GC가 없으므로 가비지를 즉시 처리 할 수 ​​있습니다. 직접 참조 계산을 구현하거나 System.Mem의 수동 GC를 사용할 수 있습니다.

하스켈 랜드에서는 외부 할당이 추적되지 않습니다. 더 많은 제어를 원하지만 사용자 정의 GC 또는 참조 카운팅이 필요없는 경우 e를 사용할 수 있습니다. 지. Foreign.Marhsal.Array 수동/범위 할당 및 할당 취소.

또 다른 옵션은 GHC RTS에서 고정 할당을 사용하는 것입니다. GC에 의해 이동되지 않는 메모리를 제공합니다. 고정 된 데이터에 대한 참조는 오버 헤드없이 외부 코드로 전달 될 수 있지만 고정 된 데이터는 추적되고 GC-d 일 수 있으며 일반적인 힙 데이터와 동일한 방식으로 GC를 트리거합니다. Here's 고정 데이터 용 API 1 개 또 다른 선택은 단순히 ByteString입니다. 고정 된 데이터의 가능한 단점은 메모리 단편화와 느린 할당이지만 안정적인 포인터를 반환하는 (모든) 외부 할당에도 적용됩니다.

1

포인터가 참조되지 않게되는 경우를 이해하는 것은 쉬운 일이 아닙니다. 내가 아는 한, 요청한 것을 수행 할 수있는 방법이 없습니다. 즉, 포인터에 더 이상 도달 할 수 없다는 것을 GC에 알리십시오. 기껏해야 GC주기를 트리거 할 수 있지만 단단한 보장은 없습니다.

설명에서 가비지 수집 대신 참조 계산 메커니즘을 사용하는 것이 좋습니다. 그러나 복잡한 순수 코드에서는 특히 카운터를 증가 또는 감소해야하는 지점을 식별하기가 어렵습니다. 주 또는 IO 기반 모나드에서 이러한 부작용이 올바르게 시퀀싱되는 것이 더 쉬울 것입니다. 나머지 계산.

"1"을 넘는 참조 카운팅을 실제로 필요로하지 않는다면 어떻게 든 일반적 관용구가 할당 및 할당 해제를 처리하기 위해 with 스타일 기능을 사용하고 있습니다. 제대로 처리하기가 다소 까다로울 수 있습니다.

예를 들어, 사소한 구현은

-- very simplified code 
withMyResource :: (ResourcePtr -> IO r) -> IO r 
withMyResource action = do 
    p <- allocResourcePtr 
    result <- action p 
    deallocResourcePtr p 
    return result 

수 이것은 다음 하나는 포인터를 반환 할 수 있기 때문에이 라이브를하고, 완전히 안전하지 않습니다 것을

withResource $ \ptr -> do 
    use ptr 

주를 사용할 수 있습니다 할당 해제 후

ptr <- withResource return 
use ptr -- dangerous! 

올바르게 포인터 처리 루틴 ne는 ST 모나드와 그 태그가 붙은 STRef과 같이 작동해야합니다. 포인터는 의도 한 범위를 벗어나지 않도록 설계되었습니다 (위와 동일). 이것은 2 등급 유형을 이용하지만 효과적입니다.

여전히 순진한 with 루틴으로 살 수 있으며 포인터가 이탈하지 않도록주의하십시오.

안전하지 않은 문제는 action이 예외를 throw 할 수 있기 때문에 발생합니다. (이는 라이브러리의 bracket 루틴을 사용하여 처리 할 수 ​​있습니다.)