ADOConnection.ExecuteでOracle.exeがメモリーリークする

[戻る]
MoonFull 2010/08/20(金) 17:39:36
開発環境
OS:WindwosXP SP3
VC++6.0
Oracle 10.2.0.1
MDAC 2.81.1132.0

上記環境でADOでDBの書込み処理を行うと、
Oracle.exeがメモリーリークを起こしてしまいます。

以下ソースの抜粋です。

void CxxxDlg::DbOpen()
{
::CoInitialize(NULL);

_ConnectionPtr m_AdoCon;// ADOコネクトオブジェクト

hr = m_AdoCon.CreateInstance(__uuidof(Connection));
m_AdoCon->CursorLocation = (enum CursorLocationEnum)3;//クライアントサイドカー
ソル

hr = m_AdoCon->Open("Provider=MSDAORA;CONNECTSTRING=XXX;User 
Id=XXX;Password=XXX", "", "", adConnectUnspecified);
}

void CxxxDlg::ExecuteSQL(LPCTSTR szSQL) 
{
long lOption = adCmdText;
BSTR bstrQuery;
bstrQuery = NULL;
char* psz = new char[2048];
::memset(psz,0,sizeof(psz));

wsprintf(psz,szSQL);
bstrQuery = _com_util::ConvertStringToBSTR(psz);
m_AdoCon->Execute( bstrQuery ,NULL,lOption);

SysFreeString(bstrQuery);
delete [] psz;
}


void DbClose()
{
m_AdoCon->Close();
m_AdoCon= NULL;

::CoUninitialize();
}
----------------------------------------------

DBOpen後、ExecuteSQL関数でテーブルのInsert,Update,Deleteを
レコード1件ずつ行っています。
1000件Insertする場合は1000回呼ばれます。
ループを繰り返すと、アプリのメモリは変わらず、
Oracle.exeのメモリが上昇します。

何故メモリーがリークするのか、解決方法がありましたら、ご教授願います。

よろしくお願いいたします。

PATIO 2010/08/20(金) 18:27:57
以下の二点に関して疑問を感じます。

・メモリが上昇すると言うのは何を根拠に書いているのか。

・メモリの使用量が上昇すると言う意味だとしてその事が
 そのままメモリリークしていると言う事になるのか。

adoを使わなければ、同等と思われる処理を行っても
Oracle.exeのメモリ使用量は上昇しないのでしょうか?

その辺りの話も気になりますね。

ITO 2010/08/20(金) 20:32:17
まず、
 ・デバッグモードで実行してリークすると思うタイミングで終了する。
 ・表示されないときもあるみたいですが、メモリーリークすると「Memory Leak」
  というようなコメントが表示される。
ですね。

「Memory Leak」のコメント以降の表示をここに公開すると何か回答が出来るかも知れま
せん。

ITO 2010/08/20(金) 20:38:47
ん?、
 Connectと自作のExecuteSQL関数が終了したことを確かめて、から次の処理を実行して
いま
すか?
特に、自作のExecuteSQL関数で、「new」「delete」の処理をしているのが気になります
ね。

MoonFull 2010/08/23(月) 10:33:43
PATIOさん、ITOさん返信ありがとうございます。


> ・メモリが上昇すると言うのは何を根拠に書いているのか。
> 
> ・メモリの使用量が上昇すると言う意味だとしてその事が
>  そのままメモリリークしていると言う事になるのか。

1000件レコードを1件ずつInsertして、その1000件を1件ずつDeleteするというループ処
理を延々とやっています。
すると、Oracle.exeが2GBまで上昇し、その後、DB書込みエラーとなります。

> adoを使わなければ、同等と思われる処理を行っても
> Oracle.exeのメモリ使用量は上昇しないのでしょうか?

adoを使わない場合、oo4oのODynaSetを使用して書込みを行うとメモリは上昇しません。
また、今回のソースはSQLSeverにAODで接続してる別のアプリを参考に作成してるのです
が、そっちのADOConnection.Executeではメモリが上昇していません。

>  Connectと自作のExecuteSQL関数が終了したことを確かめて、から次の処理を実行し
> ていま
> すか?
> 特に、自作のExecuteSQL関数で、「new」「delete」の処理をしているのが気になりま
> すね。

ConnectのOpenとCloseはアプリ起動時と終了時に行っています。
シングルスレッドで行っているためExecuteSQL関数が終了してから次のExecuteSQL関数
を呼んでいます。
また、アプリのメモリ使用量は増えていない為、、「new」「delete」での解放漏れ等は
ないと考えています。

bun 2010/08/23(月) 11:41:19
気になるのが、ConnectのOpenとCloseをループ中でやってみるとどうなるか?
それで解決するようなら、ループ中に必要な処理が何か抜けています。

メモリリークとは微妙に違う、メモリパンクではないかと推測します。

例えば、CFileクラスには CFile::Flush() というメンバがいます。
Flush()せずに書き込みまくれば、バッファがパンクするわけです。

同様に、Connection::Execute()に対しても、Flush()のような
ものが存在するのではないかと。
それが何かは分かりませんでしたが、Close() & Open() なら結果として同様の
ことが起きるので問題解決するのでは?ということです。

ただ、いちいちClose() & Open() だと遅そうなので、
Flush()に当たるものを探すことをお勧めします。

しま 2010/08/23(月) 12:44:31
>1000件レコードを1件ずつInsertして、その1000件を1件ずつDeleteするという
>ループ処理を延々とやっています。
>すると、Oracle.exeが2GBまで上昇し、その後、DB書込みエラーとなります。

オラクルのメモリー使用量が増加するのはどのようにして確認しているか
書いたほうが読む人に親切だと思います
それと、メモリーの使用量が増加するというだけではメモリーリークだと
決めらないと思いますよ


ところでトランザクションは行っていますか?

以下のページは参考になりますか?
http://support.microsoft.com/kb/198024/ja

MoonFull 2010/08/23(月) 18:12:56
bunさん、しまさん返信ありがとうございます。

> 気になるのが、ConnectのOpenとCloseをループ中でやってみるとどうなるか?

試してみたところ、メモリの増加しませんでした。
最低限の処理として使えそうです。
ありがとうございます。
CFile::Flush()にあたるものを調査してみたいと思います。

> オラクルのメモリー使用量が増加するのはどのようにして確認しているか
> 書いたほうが読む人に親切だと思います

リークの調査はパフォーマンスモニタで、Oracle.exeのPage File Bytesで確認していま
す。

> ところでトランザクションは行っていますか?

今回の処理ではトランザクションは行っていません。

PATIO 2010/08/24(火) 09:36:59
オラクルから見たらきちんと処理した結果、メモリの開放タイミングがない為に
メモリが開放されずに増え続けて最終的にオラクル側で処理できない状態になっているの
であれば、これはメモリリークとは言わないと思います。

メモリリークと言うのは内部で管理して開放されるべきタイミングで開放されていない状
況を指すわけで、外部からの指示が無いと開放できない場合はこれに当たりません。
ですから、単純にメモリの使用量が増え続けると言うだけでメモリリークとはいえないわ
けです。
オラクルを使う側の使い方に問題がある場合、オラクルのメモリリークとは言いません。

意識してトランザクションを使っていなくてもOpen時にトランザクションスタートされて
いたりしませんかね。
話を聞いている限りではADOの中で何かやっているのではないかと言う気がします。
なんとなく、トランザクションが溜まりすぎてエラーとかそういう挙動に似ている気がし
ますけれど。

単純にメモリリークと書いてしまうとオラクルの不具合みたいに聞こえますから
言葉の使い方の問題ですけれど、気をつけた方が良いと思います。

PATIO 2010/08/24(火) 09:40:28
ちょっと日本語が変なので補足。

> メモリリークと言うのは内部で管理して開放されるべきタイミングで開放されて
> いない状況を指すわけで、

メモリリークと言うのは内部で管理されているメモリが解放されるべきタイミングで
解放されていない状況を指すわけで。

うっ、開放ではなくて解放ですね。
読み替えてください。(^^;

MoonFull 2010/08/25(水) 17:31:10
[[解決]]
> オラクルから見たらきちんと処理した結果、メモリの開放タイミングがない為に
> メモリが開放されずに増え続けて最終的にオラクル側で処理できない状態になってい
> るの
> であれば、これはメモリリークとは言わないと思います。

メモリの上昇 = メモリーリーク
という認識でいました。以後改めたいと思います。
ご指摘ありがとうございます。

とりあえず、bun さんにアドバイスしていただいたとおりに
Connect::Execute()時、毎回Open Closeするということで対応することになりましたの
で
これで解決としたいと思います。

皆々様、本当にありがとうございました。

ITO 2010/08/25(水) 19:45:32
 解決済みですが、ODBC-SDKを使ったときはドライバーのエラーを見るコマンドが
ありました。
 ADOはないでしょうか?
 オラクルのメモリー使用量が上昇するぐらいですから何かエラーステータスでていて
もおかしくないです。
 昔調べてみた記憶だと、オラクルのエラーは皆英語です。
 

古いスレッドには追加発言できません。