.NETでのメモリ処理

.NETでのメモリ管理

.NETは、管理ヒープと呼ばれるメモリの特別な部分にオブジェクトを保持します。

その管理ヒープがいっぱいになると、ガベージコレクターGC)と呼ばれる特別なプロセスが開始されます。このプロセスでは、使用されなくなったオブジェクトをクリーンアップし、メモリから削除します。

Open eVision特異性

Open eVisionの管理対象オブジェクトは、DLLのヒープメモリ内の管理対象メモリ空間の外部に格納されているC++オブジェクトにリンクされています。

Open eVisionオブジェクトの.NET側はC++側よりも大幅に小さいため:
メモリ使用量は通常、GC計算よりも(はるかに)大きくなります。
GCは、必要なときにメモリを解放できません。
そのため、Open eVision管理オブジェクトを使用する.NETアプリケーションでは、管理オブジェクトが不要になったときに.Dispose()を呼び出すことは重要です。

これにより、C++メモリが解放され、GCが効率的に動作できるようになります。

.Dispose()を呼び出すタイミング

オブジェクトが不要になったらすぐに.Dispose()を呼び出します。

シンプルなケース

// Create finder
EPatterFinder finder = new EPatternFinder()
...
// Use finder
finder.Find(image);
...
// Finder has done its job, dispose
finder.Dispose();

ただし、以下に示すように、特に一時的な値とネストされたクラスでは、いくつかの特殊なケースに注意してください。

一時的な値

// Call EasyMatrixCode2 Reader
mxc2Reader.Read(image);

// Get the first MXC decoded string
string decodedString = mxc2Reader.ReadResults[0].DecodedString;

// Cleanup
mxc2Reader.Dispose();
上記のコード例について:
It seems pretty straightforward but mxc2Reader.ReadResults[0] returns a temporary EMatrixCode object that you should dispose of too.
If called a few times, it does not pose any real problem.
数千回呼び出されると、メモリの問題につながる可能性があります。
正しい安全なコードは次のとおりです。
// Call EasyMatrixCode2 Reader
mxc2Reader.Read(image);


// Get the first MXC decoded string
EMatrixCode code = mxc2Reader.ReadResults[0];
string decodedString = code.DecodedString;


// Cleanup
code.Dispose();
mxc2Reader.Dispose();

ネストされたオブジェクト

一部のOpen eVisionオブジェクトには、他のオブジェクトがネストされています。In that case, when you use the nested object, it is important to dispose of it before its host.

As an example, let's take the case of the EImageEncoder class of EasyObject2:
// Set the segmentation method to GrayscaleDoubleThreshold
encoder.SegmentationMethod= ESegmentationMethod.GrayscaleDoubleThreshold;


// Configure the segmenter object
encoder.GrayscaleDoubleThresholdSegmenter.HighThreshold = 150; 
encoder.GrayscaleDoubleThresholdSegmenter.LowThreshold = 50;
 
// Cleanup
encoder.Dispose();
GrayscaleDoubleThresholdSegmenterEImageEncoderクラス内にネストされたセグメンターオブジェクトです。
encoder.GrayscaleDoubleThresholdSegmenter.HighThreshold = 150および...LowThreshold = 50行でアクセスすると、そのセグメンターの周りにラッパーが作成されるので、メモリの問題を回避するために解放する必要があります。
正しい安全なコードは次のとおりです。
// Set the segmentation method to GrayscaleDoubleThreshold
encoder.SegmentationMethod= ESegmentationMethod.GrayscaleDoubleThreshold;

// Retrieve the segmenter object
EGrayscaleDoubleThresholdSegmenter segmenter = encoder.GrayscaleDoubleThresholdSegmenter;


// Configure the segmenter
segmenter.HighThreshold = 150; 
segmenter.LowThreshold = 50;
 
// Cleanup
segmenter.Dispose();
encoder.Dispose();

アプリケーションのクラッシュを防ぐため、ネストされたオブジェクトは必ずホストオブジェクトの前に解放してください。

正しい方法:usingステートメントを使用

変数を管理し、解放が正しく行われるようにするためのエレガントな方法は、usingステートメントでコーディングすることです。

次のようにコードを書く代わりに:
EMatrixCodeReader reader = new EMatrixCodeReader();
...
reader.Dispose();
usingステートメントを使用して、ステートメントが閉じたときに.Dispose()が自動的にreaderを呼び出すようにします。
using (EMatrixCodeReader reader = new EMatrixCodeReader()) 
{
    ...
}

関数のスコープと制限

void function()
{
  EMatrixCodeReader reader = new EMatrixCodeReader();
  ...
}

In the above code, when the variable is released at the end of the function scope, you can believe that it is not necessary to call .Dispose() on a corresponding object.

However, the object is not automatically disposed of at the end of the function, even if the variable itself does not exist anymore.

実際には、関数の最後で:
オブジェクトが解放されます。
GCはオブジェクトを解放できますが、GCは必要な場合にのみメモリを解放するため、これは即時ではありません。
時間がかかる場合があるため、C++メモリがすでにいっぱいになっていると、十分な効率が得られない場合があります。
正しい安全なコードは次のとおりです。
void function()
{
  EMatrixCodeReader reader = new EMatrixCodeReader();
  ...
  reader.Dispose();
}

関数の引数を解放する

.NETでは、Open eVisionオブジェクトは常にコピーなしで参照として渡されます。これは、関数内のオブジェクトが、呼び出しコードで関数に渡されたものと同じであることを意味します。

void UseImage(EImageBW8 imageInFunction)
{
  imageInFunction.SetSize(128, 128);
  ...
}

void MainFunction()
{
  EImageBW8 imageOutOfFunction = new EImageBW8();
  UseImage(imageOutOfFunction);
}
上記のコード例では:
imageInFunctionおよびimageOutOfFunctionは、実際には同じ画像です。
When you call .Dispose() on one image, both are disposed of.
関数の引数で.Dispose()を呼び出しますが、オブジェクトが不要になった場合のみ、関数の内側でも外側でも呼び出しません。

To have a better view of an object lifetime, it is recommended, whenever possible, to dispose of the objects in the same scope as their creation.

正しい安全なコードは次のとおりです。
void UseImage(EImageBW8 imageInFunction)
{
  imageInFunction.SetSize(128, 128);
  ...
}

void MainFunction()
{
  EImageBW8 imageOutOfFunction = new EImageBW8();
  UseImage(imageOutOfFunction);
  imageOutOfFunction.Dispose();
}

正しい方法:変数をnullに設定する

オブジェクトを解放した後、変数をnullに設定します。
これは必須ではありませんが、正しい方法と見なされます。
オブジェクトへの参照のリンクを解除し、オブジェクトが使用されなくなったことをGCに通知します。
GCは、次回の実行時にオブジェクトをクリーンアップする可能性が高くなります。
例:
// Cleanup
code.Dispose();
code = null;