DLLに対してString型のポインターを引数として渡して、返り値がその引数に
入ると言う処理があるのですが、その引数は、String型をSetLengthで領域確保
しないとエラーになってしまいます。
そこで以下のようにしているのですが、大量のデータを繰り替えし処理すると
メモリーがどんどん増えて言ってしまいます。
var
Data:String;
begin
〜 略 〜
SetLength(data,2048);
Dll処理(@Data);
result := PChar(data);
〜 略 〜
end;
String型のSetLengthが原因であろう所までは調べられたのですが、String型の
領域クリアの方法がわからずこまっています。
どなたか方法をご存知の方よろしくお願いします。
補足・・・
Pcharとかでいろいろと思考錯誤しましたが、結局SetLengthをしなければ
DLLを読む事が出来ない事は確かです。
Data := '';
string + SetLength() をメモリバッファとして使ってるかぎり、
メモリについて心配する必要はないです。
普通は
PChar + GetMem() + FreeMem() を使います。
えーとさん。
もちろん、一番最初にやりました。
が、メモリは増える一方なのです。
ヘルプを見る限り、SetLengthはその領域のメモリーを確保すると
なっており、その廃棄方法が書いていないので困っています。
空白の代入では廃棄されないようです。
気にする必要はないです。
> その廃棄方法が書いていないので困っています。
参照数がゼロの長い文字列がいつガベージコレクトされるかなんて、誰にも
わかりません。気にするんでしたら、前に書きましたように文字列をバッファ
にするのをやめて
PChar + GetMem() + FreeMem()
を使ってください。
むくさん、こんにちは。
むくさんのコードですが、ローカル変数Dataのポインタを
Resultに代入していますよね?
これはちょっとおかしくはないですか?
えーとさん。
気にする必要なければ困らないんですが。
現実にメモリーが増えてしまいメモリーオーバーで処理が止まるので。
PChar + GetMem() + FreeMem() は一番初めにやりました。
これが出来れば苦労しないんですよね〜。
Dllに対してはString型をSetLengthして渡すしか方法が無く
困っています。
シャチさん。
dataには2048のうちでどこまでデータが入っているか決まってないので
このようにしてますが、おかしいでしょうか?
ひょっとしてこれが原因と言うことですか?
ちょっと考えてみます。
DLL側で戻り値のためのメモリを確保するのではなく、呼び出し側でメモリを確保してから、そのアドレスをPCharでDLLに渡すべきでは?
逆は真さん。
DLL側がString型のポインター以外受付けないんです。
DLL作成者の意図が不明なのでなぜかは答えられませんが。
Pcharのアドレスを渡すにしても、一度String型をSetLengthし
Pcharにキャストする事になり、結果は何もかわらないんです。
procedure foo;
var
Data: array of char;
begin
〜 略 〜
SetLength(data,2048);
Dll処理(@Data);
result := PChar(Data);
〜 略 〜
end;
のようにDataが動的配列ならばDataを開放する場合Data:=nil;ですが、そのほか明示的にFinalizeを使う手もあります。しかし、この関数の中で破棄するわけではないようですね。
それから
> result := PChar(Data);
はresult := PChar(@Data[0]);ですよね
DLL側の関数の引数にStringがあるんですか?
であれば、
ShareMemユニットとBORLNDMM.DLLを利用する必要があるのでは?
これらを使ってもなお、メモリリークしているのでしょうか。
> dataには2048のうちでどこまでデータが入っているか決まってないので
> このようにしてますが、
SetLength手続きは新しく割り当てられた空間を初期化しませんから、
変数をDLLに渡す前にFillCharでゼロクリアしておくとよいと思います。
結果が返ってきたらStrLenで長さを取得できます。
> おかしいでしょうか?
result := PChar(data);
この瞬間に参照カウントが増えるんじゃないでしょうか?
参照カウントが増えればDataは破棄されなくなるのでは?
結局その DLL のインポート部分を見てみないとなんともいえませんね。
その DLL 内でリークってことはないですよね?
インタフェースの部分でしたらどうにでもなります。
> DLL側がString型のポインター以外受付けないんです。
これが意味不明です。PString ってことなら、変な DLL ですね。
もし、PChar であって、それが GetMem() したものを受け付けないとすると、
DLL として変です。
書込み頂いた皆様。
>これが意味不明です。PString ってことなら、変な DLL ですね。
>もし、PChar であって、それが GetMem() したものを受け付けないとすると、
>DLL として変です。
ごもっともです。DLLの間違いと言うかDLLがいけないんじゃないかと
感じています。ですが、これしか方法がないのでどうにかするしかない
のかと思ってあきらめてます。
いろいろなご意見を頂いていろいろと試していますがなかなかうまく
いきません。
Pcharのポインタ型で引数を指定すればStringにこだわる事はなくなった
のですが、FreeMemしてもまだどこかでリークしてしまいます。
多分詳細なコードを見てもらわない限り判断が難しい所まできてしまって
いるよなので、未解決ですが身を引きます。
ツイート | ![]() |