2017-12-29 38 views
1

FFI経由でデータを割り当ててファイナライザを関連付けると、Haskellで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を使用できます。 g。 Foreign.Marhsal.Arrayは、手動/スコープ割り当ておよび割り当て解除用です。

別のオプションは、GHC RTSで固定割り当てを使用することです。これにより、GCによって移動されないメモリが得られます。固定データへの参照はオーバーヘッドなしで外部コードに渡すことができますが、固定データは追跡され、GC-dになり、通常のヒープデータと同じ方法でGCを起動します。 Here's固定データの1つのAPI。別の選択肢は単にByteStringです。固定データの潜在的な欠点は、メモリ断片化と低速割り当てですが、安定ポインタを返す(任意の)外部割り当てに対しても保持されます。

1

ポインタが参照されなくなったときの理解は簡単ではありません。 私が知る限り、要求するものを実行する方法はありません。つまり、ポインタに到達できなくなったことをGCに通知してください。せいぜい、GCサイクルを引き起こすことはできますが、厳しい保証はありません。

あなたの説明から、おそらくガベージコレクションの代わりに参照カウントメカニズムが好まれます。しかし、複雑な純粋なコードでは、カウンターをインクリメントまたはデクリメントするポイントを特定することは困難です。ステートまたはIOベースのモナドでは、そのような副作用が適切に順序付けされている方が簡単です。残りの計算。

「1」を超えて参照カウントを行う必要がない場合は、何らかの共通のイディオムが割り当てと割り当て解除を処理するためにwithスタイル関数を使用しています。 これは、正しく処理するのが少し難しい場合があります。例えば

、些細な実装では、これはその後、1ライブそれを作る、ポインタを返す場合がありますので、これは、完全に安全ではないことを

withResource $ \ptr -> do 
    use ptr 

ノートとして使用することができます

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

可能性がありその割り振り解除後に

ptr <- withResource return 
use ptr -- dangerous! 

適切にポインタ処理ルーチンneはSTモナドとそのタグ付きSTRefのように動作するはずです。これはポインタが意図したスコープをエスケープしないように設計されています。これはランク2の型を悪用しますが、効果的です。

でも、ナイーブなwithルーチンで生きていて、ポインタをエスケープしないように注意してください。

もう1つ安全でない問題は、actionが例外をスローすることによって発生します。 (これは、ライブラリのbracketのようなルーチンを使用して処理できます)。

関連する問題