最近、ロックされたビットマップを頻繁に使用していますが、「無効なメモリにアクセスしようとしました」というエラーが発生し続けます。これは主に、ビットマップがメモリ内で移動されたためです。GCHandle.Alloc()
CLRにメモリを割り当てて固定するために使用する人もいます。同じことをしますかBitmap.LockBits()
?「ロック」メモリと「ピン」メモリの違いがわかりません。用語と違いがある場合は、それについても説明できますか?
2 に答える
GCHandle.Alloc
はより一般的な方法であり、任意の管理対象オブジェクトにハンドルを割り当てて、それをメモリに固定する(または固定しない)ことができます。メモリを固定すると、GCがメモリを移動できなくなります。これは、配列などのデータをアンマネージコードに渡す必要がある場合に特に便利です。
GCHandle.Alloc
このオブジェクトを固定すると、管理対象オブジェクト(ビットマップオブジェクト)が移動する(およびガベージコレクションされる)のを防ぐだけなので、ビットマップのデータにアクセスするのに役立ちません。
ただし、ビットマップはネイティブGDI+のBITMAP
構造のラッパーです。固定する必要のある管理対象配列にデータを保持するのではなく、GDI+ビットマップオブジェクトへのネイティブハンドルを管理するだけです。そのため、Bitmap.LockBits
このビットマップに、そのメモリへのアクセスに関心があることを伝える方法であり、GdipBitmapLockBits
関数の単なるラッパーです。したがって、それを呼び出す必要性は、GCを使用して管理された環境で作業しているという事実よりも、GDI+ビットマップを使用しているという事実と関係があります。
使用LockBits
すると、ポインタを使用してそのメモリにアクセスできるようになります。これBitmapData.Scan0
は、データの最初のバイトのアドレスです。背後のメモリにアクセスしない限り、問題は発生しないはずですBitmapData.Scan0 + Height * Stride
。
そして、あなたが終わったときに覚えておいてUnlockBits
ください。
あなたの場合、attempted to access invalid memory
エラーはおそらくコードの安全でない部分で行っている無効なメモリ割り当てが原因です。たとえば、割り当てられた配列は、そこに入れようとしているピクセル数よりも小さいです。
また、85K未満のオブジェクトのみがメモリに移動されるため、画像データが85000バイト未満でない限り、オブジェクトの固定について考える必要はありません。
もう1つの話は、処理を高速化するために、たとえばc++ライブラリでオブジェクトをアンマネージコードに渡す場合です。この場合、渡された画像がスコープ外になり、ガベージコレクションが行われると、例外が発生する可能性が非常に高くなります。この場合、 GCHandle.Alloc(imageArray,GCHandleType.Pinned);
を使用して、不要になった場合はFreeを呼び出すことができます。