2017-12-03 3 views
9

runtime.SetFinalizerを使用して登録されたファイナライザの総数を取得する方法はありますか?ファイナライザ統計

mallocを使用して割り当てられたメモリを解放するために、いくつかの製品に登録済みのファイナライザを追加することを検討しています。その場合、オブジェクトの割り当て率は比較的高くなる可能性があります。ファイナライザの数を監視し、重複しないようにして(他のガベージコレクタと同じように)メモリ不足エラーが発生しないようにすることができればうれしいでしょう。

(私は明示的に割り当て解除は、この問題を回避することを認識してんだけど、私たちはClose機能またはそのような何かを呼び出さない既存のコードを、変更することはできません。)

答えて

4

あなたはこれらのカウントを保持維持することができます新しいオブジェクトが作成され、ファイナライズされたときに、それぞれ、未実装のパッケージ変数をインクリメントおよびデクリメントすることによって、オブジェクトを生成します。例えば

package main 

import (
    "fmt" 
    "runtime" 
    "sync/atomic" 
) 

var totalObjects int32 

func TotalObjects() int32 { 
    return atomic.LoadInt32(&totalObjects) 
} 

type Object struct { 
    p uintptr // C allocated pointer 
} 

func NewObject() *Object { 
    o := &Object{ 
    } 
    // TODO: perform other initializations 
    atomic.AddInt32(&totalObjects, 1) 
    runtime.SetFinalizer(o, (*Object).finalizer) 
    return o 
} 

func (o *Object) finalizer() { 
    atomic.AddInt32(&totalObjects, -1) 
    // TODO: perform finalizations 
} 

func main() { 
    fmt.Println("Total objects:", TotalObjects()) 
    for i := 0; i < 100; i++ { 
     _ = NewObject() 
     runtime.GC() 
    } 
    fmt.Println("Total objects:", TotalObjects()) 
} 

https://play.golang.org/p/n35QABBIcj

+0

私が関与するすべてのソースにパッチを適用することはできませんので、私は、ランタイム自体にこれを入れなければならないだろうと思います。しかしファイナライザの登録を解除することは可能ですので、カウントは重要ではありません。私はランタイム自体からカウンターを集めるための何らかの方法を望んでいました。 –

0

それはあなたのためのカウントを行いruntime.SetFinalizerにラッパーを作成することが可能です。もちろん、それはどこでもあなたが使うSetFinalizerを使用することの問題です。

問題がある場合はSetFinalizerソースコードを直接変更することもできますが、それにはa modified Go compilerが必要です。

アトミック整数は、異なるスレッドで呼び出される可能性があります。そうしないと、競合状態が発生する可能性がないため、カウンタが正確でない可能性があります。 Golangは、ファイナライザが単一のゴルーチンから呼び出されることを保証しているため、内部関数には必要ありません。

https://play.golang.org/p/KKCH2UwTFYw

package main 

import (
    "fmt" 
    "reflect" 
    "runtime" 
    "sync/atomic" 
) 

var finalizersCreated int64 
var finalizersRan int64 

func SetFinalizer(obj interface{}, finalizer interface{}) { 
    finType := reflect.TypeOf(finalizer) 
    funcType := reflect.FuncOf([]reflect.Type{finType.In(0)}, nil, false) 
    f := reflect.MakeFunc(funcType, func(args []reflect.Value) []reflect.Value { 
     finalizersRan++ 
     return reflect.ValueOf(finalizer).Call([]reflect.Value{args[0]}) 
    }) 
    runtime.SetFinalizer(obj, f.Interface()) 
    atomic.AddInt64(&finalizersCreated, 1) 
} 

func main() { 
    v := "a" 
    SetFinalizer(&v, func(a *string) { 
     fmt.Println("Finalizer ran") 
    }) 
    fmt.Println(finalizersRan, finalizersCreated) 
    runtime.GC() 
    fmt.Println(finalizersRan, finalizersCreated) 
}