記事
· 2021年8月25日 2m read

リレーションシップの処理中に大量メモリが使用されてしまう場合の対処法について

これは InterSystems FAQ サイトの記事です。

リレーションシップが設定されており 1対n の n が多量の場合、そのリレーションシップの順次処理などで大量のメモリ消費となるケースがあります。

プログラムの中で多側オブジェクトを参照し内部的にスウィズル処理した後には、そのOREFを含む変数の解放(削除、他の値の設定など)だけでは、その多側オブジェクトとリレーションシップオブジェクトが解放されないことが原因です。

それらを完全にメモリから解放するためには、OREF変数の解放とRelationshipオブジェクトの%UnSwizzleAt<%Library.RelationshipObject >メソッドの実行による明示的なメモリ解放が必要です。
 

- 使用例 -

 Do {
    Set employee = company.Employees.GetNext(.key)
    If (employee '= "") {
        Write employee.Name,!
        // remove employee from memory
        Do company.Employees.%UnSwizzleAt(key)
    }
 } While (key '= "") 


多側オブジェクトが数個しかない場合は特に問題はありませんが、紐づいている数が大量な場合に、ループ文で連続アクセスした場合、その分大量にメモリにオブジェクトが展開され続けることになり、メモリー圧迫要因のひとつになります。

その様な状況を避けるために明示的な開放処理を入れる必要があります。

ディスカッション (6)0
続けるにはログインするか新規登録を行ってください

Kakechi さん

貴重な情報を公開いただきありがとうございます!
Relationshipオブジェクトの理解が浅く申し訳ないのですが、一点だけ教えてください。

今回の場合、Relationshipオブジェクトをループで回した際にのみ事象が発生するという理解なのですが、
Interoperabilityで利用可能なRecordMap利用時に生成される、Batchクラス内の
Recordsプロパティも上記に該当するのでしょうか?

今私が携わるシステムではRecordMapを多用しており、
数万件のデータをこの仕組みを用いて取り込みをおこなっているため、
上記の事象が発生するのではないかと懸念しております。

Ohata様

こんにちは、ご質問ありがとうございます。
Interoperabilityの場合、RecordMapのBatchサービスでは内部で対応しているため明示的に%UnSwizzleAt() する必要はありません。
また、オペレーションについても UnSwizzleRecordsプロパティ(デフォルトはTrue:チェックあり)により、処理後にメモリから解放されるため、こちらについても明示的に %UnSwizzleAt() する必要はありません。
UnSwizzleRecordsプロパティを 0 (False:チェックなし) に指定し大量のデータを処理する場合には、正しく開放処理を行わないと <STORE> エラーになる場合がありますのでご注意ください。

Kakechi さん

回答いただきありがとうございます!
BSもBOも標準のまま利用するのであれば開放処理がシステム内で行われると理解しました。

私が作成しているシステムでは、BS/BP/BOをそれぞれ標準を継承してカスタマイズしたり、
Batch.RecordをObjectScript内でループさせて利用するような処理もあるのですが、
この場合には%UnSwizzleAt()が必要との理解でよろしいでしょうか?

例)
BSでファイル検知を行い、RecordMapの仕組みを利用してファイルからBatchクラスを生成。

BOに連携し、BatchクラスをObjectScript内のクラスに譲与。

取得したBatch.Recordの内容をループで回しながら処理を実行。

このループの中では%UnSwizzleAt()が必要?
もしくはInteroperabilityのプロセスで実行する処理の中では、
BatchクラスのRecordの内容は勝手に開放される?

Ohata様

継承しているBOのクラスが、EnsLib.RecordMap.Operation.Batch* のクラスである場合は、 UnSwizzleRecords プロパティをオーバーライドして変更していない限り、デフォルトの True(=1) となるため、明示的に %UnSwizzleAt() する必要はありません。

「BatchクラスをObjectScript内のクラスに譲与」というのが、例えば %Persistent などのユーザ作成クラスに対してである場合は、別途 %UnSwizzleAt() していただく必要があります。

どのような構成にしているかによって変わってくるところはありますので、詳細についてのご相談があれば弊社サポートセンター(jpnsup@intersystems.com)までお気軽にお問い合わせください。