05-16-2014, 07:21 PM
★point
RecordGrid.columns に設定するRecordGridColumnの配列は、フィールドで定義するな!
下記の数値は、RecordGridUI.get-cell-at で、
1回につき、100レコード×100カラム のセルを取得した場合の、
メモリの使用量の推移です。
※Curlのメモリ使用量は、「タスクマネージャ」の「プロセス」タブで表示される
「surge,.exe」の「メモリ(プライベートワーキングセット)」を参照しました
■セル取得時のメモリ使用量
①「field定義のカラムを利用」した場合のメモリ消費量(単位は100KB)
1回目: 508 差分
2回目: 791 283
3回目:1074 283
4回目:1347 273
5回目:1629 282
6回目:1894 265
7回目:2195 301
②「一時的なカラムを利用」した場合のメモリ消費量(単位は100KB)
1回目: 549 差分
2回目: 791 242
3回目:1075 284
4回目:1347 272
5回目:1367 20
6回目:1383 16
7回目:1407 24
①と②の違いは、下記のアプレットのコードを見てもらうとわかりますが、
簡単に言うと、RecordGrid.columns に設定する{Array-of RecordGridColumn} を、
クラスのフィールド(field)に定義して利用するか、そうでないか、というものです。
数値の推移をみてもわかるように、フィールドで定義して利用した①には、
単純増加傾向がみられるのに比べ、
そうではない②は、4回目以降、メモリの使用増加量が低下しています。
①については、私が試した限りでは20回以上、単純増加傾向か続きました。
また、各処理の間で、明示的に「ガベージコレクト(garbage-collect)」を呼び出した場合も、
①ではその効果がみられませんでした。
プログラムでは、グリッドを毎回作り直しているので、
以前のグリッド内で生成されたセルは、ガベージとして認識され、破棄されてほしいところですが、
私の試した限りでは、そのように期待した結果にはなりませんでした。
どうも、フィールドで定義したカラムを利用して生成されたセルは、
そのフィールドの親クラスが破棄されるまで、
ずっとガベージとして認識されないのではないかと推測されるのです。
静的に、グリッドとカラムを保持するような画面であればよいのですが、
グリッドに対して何度もカラムの再設定をする処理のある画面では、
上記のように、メモリの使用量がどんどん増えてしまう、
という問題が起こる可能性があります。
今回私が試した環境は、Windows7+Curl8.0.4 だけですので、
この現象が、ほかの環境でも発生するかは不明ですが、
できるだけ、RecordGridColumn の配列は、フィールドで定義せず、
記載したアプレットのサンプルソースのようにgetterで一時的に作成するなどの方式にしたほうがよさそうです。
RecordGrid.columns に設定するRecordGridColumnの配列は、フィールドで定義するな!
下記の数値は、RecordGridUI.get-cell-at で、
1回につき、100レコード×100カラム のセルを取得した場合の、
メモリの使用量の推移です。
※Curlのメモリ使用量は、「タスクマネージャ」の「プロセス」タブで表示される
「surge,.exe」の「メモリ(プライベートワーキングセット)」を参照しました
■セル取得時のメモリ使用量
①「field定義のカラムを利用」した場合のメモリ消費量(単位は100KB)
1回目: 508 差分
2回目: 791 283
3回目:1074 283
4回目:1347 273
5回目:1629 282
6回目:1894 265
7回目:2195 301
②「一時的なカラムを利用」した場合のメモリ消費量(単位は100KB)
1回目: 549 差分
2回目: 791 242
3回目:1075 284
4回目:1347 272
5回目:1367 20
6回目:1383 16
7回目:1407 24
①と②の違いは、下記のアプレットのコードを見てもらうとわかりますが、
簡単に言うと、RecordGrid.columns に設定する{Array-of RecordGridColumn} を、
クラスのフィールド(field)に定義して利用するか、そうでないか、というものです。
Code:
{define-class public Screen {inherits Dialog}
||レコードとカラムの数
field rs-size:int = 100
field rf-size:int = 100
||フィールドとして定義するレコードグリッドカラムの配列
field ary-column:{Array-of RecordGridColumn}
||一時的なレコードグリッドカラムの配列を返却するゲッター
{getter {tmp-ary-column}:{Array-of RecordGridColumn}
{return {self.make-columms}}
}
{constructor public {default}
set self.ary-column = {self.make-columms}
def ary-rf = {{Array-of RecordField}}
{for i:int = 0 below self.rf-size do
{ary-rf.append
{RecordField {String i}, nullable? = true}
}
}
def rs =
{RecordSet
{RecordFields {splice ary-rf} }
}
{for i:int = 0 below self.rs-size do
def new-r = {rs.new-record}
{rs.append new-r}
}
def cb-permanent =
{CommandButton
label = "field定義のカラムを利用する",
{on Action do
{self.get-cell rs, self.ary-column}
}
}
def cb-tmp =
{CommandButton
label = "一時的なカラムを利用する",
{on Action do
{self.get-cell rs, self.tmp-ary-column}
}
}
def cb-gc =
{CommandButton
label = "ガベージコレクト",
{on Action do
{garbage-collect}
}
}
{self.add
{VBox
cb-permanent,
cb-tmp,
cb-gc
}
}
}
||セルを取得すrう
{method {get-cell
record-set:RecordSet,
cols:{Array-of RecordGridColumn}
}:void
let cnt:int = 0
def grid = {RecordGrid }
set grid.columns = cols
set grid.record-source = record-set
{for r in grid.records do
{for col in grid.columns do
def cell = {grid.ui.get-cell-at r, col}
{if-non-null cell then
set cnt = cnt + 1
else
{output "cell が見つかりません"}
}
}
}
{output cnt & "個のセルを生成しました"}
}
||大量のカラムを生成する
{method {make-columms}:{Array-of RecordGridColumn}
def cols = {{Array-of RecordGridColumn}}
{for i:int = 0 below self.rf-size do
{cols.append
{RecordGridColumn {String i}}
}
}
{return cols}
}
}
{def s = {Screen}}
{value s}
数値の推移をみてもわかるように、フィールドで定義して利用した①には、
単純増加傾向がみられるのに比べ、
そうではない②は、4回目以降、メモリの使用増加量が低下しています。
①については、私が試した限りでは20回以上、単純増加傾向か続きました。
また、各処理の間で、明示的に「ガベージコレクト(garbage-collect)」を呼び出した場合も、
①ではその効果がみられませんでした。
プログラムでは、グリッドを毎回作り直しているので、
以前のグリッド内で生成されたセルは、ガベージとして認識され、破棄されてほしいところですが、
私の試した限りでは、そのように期待した結果にはなりませんでした。
どうも、フィールドで定義したカラムを利用して生成されたセルは、
そのフィールドの親クラスが破棄されるまで、
ずっとガベージとして認識されないのではないかと推測されるのです。
静的に、グリッドとカラムを保持するような画面であればよいのですが、
グリッドに対して何度もカラムの再設定をする処理のある画面では、
上記のように、メモリの使用量がどんどん増えてしまう、
という問題が起こる可能性があります。
今回私が試した環境は、Windows7+Curl8.0.4 だけですので、
この現象が、ほかの環境でも発生するかは不明ですが、
できるだけ、RecordGridColumn の配列は、フィールドで定義せず、
記載したアプレットのサンプルソースのようにgetterで一時的に作成するなどの方式にしたほうがよさそうです。