[delphi-users:1021] TIBSQLからのSELECT文で「メモリ不足です」と表示される場合がある

271 views
Skip to first unread message

moru

unread,
Mar 27, 2010, 7:13:01 PM3/27/10
to delphi...@freeml.com
いつもお世話になっております。
稲庭と申します。
 
下記、環境でDBアクセスを含む重い処理を大量・長時間実行していると「メモリ不足です」と表示され、処理が中断されてしまいます。
メモリリークについては、EurekaLogによる検出はありません。
また、メモリ不足です(EOutOfMemory)の発生箇所は、EurekaLogのレポートによれば、IB.pas-IBAllocで毎回発生しています。
いろいろ試したところ、下記のようなテーブル(※)へ、TIBSQLでSELECT文(選択リストは3つ)を実行している箇所をコメントアウトすると、正常に終了することが分かっています。
(※、カラム数35(VARCHARとDOUBLE)、行数3万)
タスクマネージャーからメモリ使用量を見ても、物理メモリの半分以下の状態です。
対処方法について、お心当たりございましたら、アドバイスのほど、よろしくお願い申し上げます。
 
・Delphi7.1
・FireBird1.5.4
・IBX7.11
・現象確認OS-WindowsXPSP3、Windows7
 
他に必要な情報があれば、ご返信頂けると幸いです。
稲庭

hirari

unread,
Mar 28, 2010, 7:04:51 AM3/28/10
to delphi...@freeml.com
メモリマネージャのFastMMを使ってみるといいかもしれません。
http://sourceforge.net/projects/fastmm/

プロジェクトファイルのusesにFastMM4を追加して使います。


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
動画など大きいファイルもMLメンバーにカンタンに共有!
http://ad.freeml.com/cgi-bin/sa.cgi?id=fkfwL
-----------------------------------------------------[freeml by GMO]--

Fukushi

unread,
Mar 28, 2010, 10:41:31 AM3/28/10
to delphi...@freeml.com
稲庭さん、こんばんは。福士と申します。

> 下記、環境でDBアクセスを含む重い処理を大量・長時間実行していると「メモリ不足です」と表示され、処理が中断されてしまいます。
> メモリリークについては、EurekaLogによる検出はありません。
> また、メモリ不足です(EOutOfMemory)の発生箇所は、EurekaLogのレポートによれば、IB.pas-IBAllocで毎回発生しています。
> いろいろ試したところ、下記のようなテーブル(※)へ、TIBSQLでSELECT文(選択リストは3つ)を実行している箇所をコメントアウトすると、正常に終了することが分かっています。
> (※、カラム数35(VARCHARとDOUBLE)、行数3万)

UniDirectionalプロパティがデフォルトのFalseになっているのが
原因ではないでしょうか?IBXは双方向カーソルを実現するために
各レコードをキャッシュするようになっており、それが原因で
メモリ不足が発生することがあります。単一方向にしか移動しない
(Nextのみ)のであればUniDirectionalをTrueにすることで問題を
回避できると思います。

---
東洋テクニカルシステム株式会社 システム開発部 福士 光
Hikaru Fukushi (Toyo Technical System Inc.)
mailto:fuk...@tts-inc.co.jp


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
自分好みのMLを作成して気の合う仲間と情報を共有しよう♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=fkhIV

moru

unread,
Mar 29, 2010, 5:00:22 AM3/29/10
to delphi...@freeml.com
hirari様
ご返答ありがとうございます。
 
FastMMを使ったところ、現象の発生がなくなりました。
しかし、すでに稼働しているシステムのため、すぐに採用することは難しいです。
 
FastMMで現象が改善されたということは、メモリの断片化が問題の可能性が高いということなのでしょうか。

2010年3月28日20:04 hirari <delphi...@freeml.com>:

moru

unread,
Mar 29, 2010, 5:05:20 AM3/29/10
to delphi...@freeml.com
福士様
ご返答ありがとうございます。
 
同じ処理で、TIBDataSetに大きなデータをよみこんでいるため、ご指摘の可能性が高いかもしれません。
しかし、仕組み的に難しく、検証して確認するには至っておりません。
また、双方向である必要もあるため、単方向への変更もできません。
読み込むデータ量を減らすなどしての対応しかないでしょうか?
稲庭
2010年3月28日23:41 Fukushi <delphi...@freeml.com>:

Fukushi

unread,
Mar 29, 2010, 5:43:14 AM3/29/10
to delphi...@freeml.com
稲庭さん、こんばんは。福士です。

> 同じ処理で、TIBDataSetに大きなデータをよみこんでいるため、ご指摘の可能性が高いかもしれません。
> しかし、仕組み的に難しく、検証して確認するには至っておりません。
> また、双方向である必要もあるため、単方向への変更もできません。
> 読み込むデータ量を減らすなどしての対応しかないでしょうか?

前回も書きましたが、IBXはUniDirectionalプロパティがFalseの
ときに、本来単方向にしか移動できないデータセットに対して
双方向の移動を可能にするために、通過したレコードをキャッシュ
するようになっています。このときキャッシュに使用するメモリを
BufferChunks毎に再アロケートして内容をコピーするため、例えば
10MBのデータがキャッシュされた状況で次のレコードに移動すると
一時的に20MBのメモリを必要とするような状況が起きていたような
気がします。

# エラーとなるIB.IBAllocの呼び出し元はIBCustomDataSet.
# TIBCustomDataSet.AdjustPositionでしょうか?


hirariさんの回答にあったFastMMである程度問題が解決したと
いうことであれば、FastMM採用以前のDelphi標準のメモリ
マネージャの持つ問題が関係しているのかもしれません。解決策は
お勧め順に

1.BufferChunksを大きくしてメモリの再アロケートを減らす。
2.メモリマネージャを変更する(例えばFastMMを使用する)。
3.IBXを使うのをやめる(DBXなどに移行する)。
4.UniDirectionalをTrueにして単方向でのみ動作させる。

といったところでしょうか。参考にしてください。

# BufferChunksはキャッシュサイズの直接的な増分なので、大きめな
# 値を指定することで問題が起きにくくなるはずですが、確か4KBが
# メモリマネージャのストラテジ切り替えの閾値だったような…。

---
東洋テクニカルシステム株式会社 システム開発部 福士 光
Hikaru Fukushi (Toyo Technical System Inc.)
mailto:fuk...@tts-inc.co.jp


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
春に新しいことを始めるなら♪MLも作成して活用しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=fkrzS

moru

unread,
Mar 29, 2010, 8:00:01 PM3/29/10
to delphi...@freeml.com

福士様
詳しい説明ありがとうございます。

># エラーとなるIB.IBAllocの呼び出し元はIBCustomDataSet.
># TIBCustomDataSet.AdjustPositionでしょうか?
はい、その通りです。

>1.BufferChunksを大きくしてメモリの再アロケートを減らす。
下記の値に変えて、試してみましたがうまくいきませんでした。
 1500、2000、4000
 
>2.メモリマネージャを変更する(例えばFastMMを使用する)。
将来的に採用したいと思いますが、すぐに採用はできません。
稼働中のシステムなので、すぐ対応が必要なためです。

>3.IBXを使うのをやめる(DBXなどに移行する)。
すでに作り込んだシステムなので、移行はできません。

>4.UniDirectionalをTrueにして単方向でのみ動作させる。
これについても、修正量が多く対応が難しいです。
 
少し前にスループット改善のために、取得したデータをキャッシュするようにしてから、今回の現象が発生するようになったようです。(前よりメモリの使用量、確保解放の繰り返しが増えた)
根本的な解決にはなりませんが、いったんはデータキャッシュをやめる方向で、一時的に対応しようと考えています。(まだ、それで解決するかは未確認です)
稲庭

Fukushi

unread,
Mar 29, 2010, 9:11:56 PM3/29/10
to delphi...@freeml.com
稲庭さん、こんにちは。福士です。

> >1.BufferChunksを大きくしてメモリの再アロケートを減らす。
> 下記の値に変えて、試してみましたがうまくいきませんでした。
> 1500、2000、4000

もっと大きな値、例えば32768とか65536とか(実行環境のメモリに
余裕があるならもっと思い切って大きな値、最初からキャッシュ
データが全て入りきって再アロケートの起きる恐れのないサイズの
ほうがいいのかもしれません)を指定したらどうでしょう?少なく
とも4096以下は意味がないと思います。


> >2.メモリマネージャを変更する(例えばFastMMを使用する)。
> 将来的に採用したいと思いますが、すぐに採用はできません。
> 稼働中のシステムなので、すぐ対応が必要なためです。

それほど大きな問題だとは思わないのですが。既にDelphi 2007
以降で使用されていることで実績はありますし(FastMMはDelphi
2006以降の標準メモリマネージャです)。

# 単なるメモリマネージャの入れ替えなのでプログラムに手を
# 入れるよりは安全かと。


まぁBufferChunksの変更で解決すればベストですが。

---
東洋テクニカルシステム株式会社 システム開発部 福士 光
Hikaru Fukushi (Toyo Technical System Inc.)
mailto:fuk...@tts-inc.co.jp


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
お花見や旅行♪MLメンバーと撮った写真はみんなで楽しもう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=fkywe

moru

unread,
Mar 29, 2010, 9:42:38 PM3/29/10
to delphi...@freeml.com
福士様
返信ありがとうございます。
 
BufferChunksについてですが、
詳しくないので間違っているかもしれませんが、値は行数の指定でないでしょうか。
4000以上にしたところ、TIBCustomDataSet.AdjustPositionでなく、TIBCustomDataSet.InternalOpenからEOutOfMemoryが発生するようになりました。
(ヘルプより)
>BufferChunks を使うと,データセットが任意の時点でバッファ領域を割り当てられるレコードの数を取得または設定できます
(VCLソースより)
下記箇所で、”FBufferChunkSize := FRecordBufferSize * BufferChunks;”とされています。
TIBCustomDataSet.InternalOpen(IBCustomDataSet.pas 3282行)
 
FastMMの件、もう一度上司と相談してみます。
何度もありがとうございます。
稲庭

Fukushi

unread,
Mar 29, 2010, 10:21:19 PM3/29/10
to delphi...@freeml.com
稲庭さん、こんにちは。福士です。

> BufferChunksについてですが、
> 詳しくないので間違っているかもしれませんが、値は行数の指定でないでしょうか。

あー、そうですね。失礼しました。IBCustomDataSet.pasをちょっと
追ってみましたが、キャッシュサイズ(FCacheSize)の初期値は
TIBCustomDataSet.InternalOpen内で

| FBufferChunkSize := FRecordBufferSize * BufferChunks;

で計算されたFBufferChunkSizeと同じ値で、以後FBufferChunkSizeだけ
増えてゆくため、BufferChunksを当該SELECT文で取得されるレコードの
最大想定数として再アロケートが発生しないようにするのがいいように
思います。

ただその時点でFCacheSize分のまとまったメモリが確保できない
ような状況(標準の(FastMM系でない)メモリマネージャだとヒープ
エリアが断片化しやすく、まとまったサイズのブロックが確保
できなくなることがある)だとまずいので、そのような状況が発生
するのであれば、やはりメモリマネージャを変更する必要があるの
かもしれません。

# BufferChunksが適切でないと何度も再アロケートが発生してしまい、
# 自分で断片化の原因を作って嵌まってしまうことに…。

---
東洋テクニカルシステム株式会社 システム開発部 福士 光
Hikaru Fukushi (Toyo Technical System Inc.)
mailto:fuk...@tts-inc.co.jp


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
自分好みのMLを作成して気の合う仲間と情報を共有しよう♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=fkzhx

moru

unread,
Mar 30, 2010, 1:13:48 AM3/30/10
to delphi...@freeml.com
福士様
お世話になっております。
BufferChunksの調整で対応できなかったこと、他に短期間で修正が難しいことを踏まえて、
FastMMで対応することとなりました。
 
本当に助かりました、またありがとうございました。
今後ともよろしくお願いいたします。
稲庭
Reply all
Reply to author
Forward
0 new messages