SetLengthしたString型のメモリ領域をクリアするには?

解決


むく  2005-10-04 00:53:02  No: 17859

DLLに対してString型のポインターを引数として渡して、返り値がその引数に
入ると言う処理があるのですが、その引数は、String型をSetLengthで領域確保
しないとエラーになってしまいます。

そこで以下のようにしているのですが、大量のデータを繰り替えし処理すると
メモリーがどんどん増えて言ってしまいます。
var
 Data:String;
begin
〜  略  〜
 SetLength(data,2048);
 Dll処理(@Data);
 result := PChar(data);
〜  略  〜
end;

String型のSetLengthが原因であろう所までは調べられたのですが、String型の
領域クリアの方法がわからずこまっています。
どなたか方法をご存知の方よろしくお願いします。

補足・・・
  Pcharとかでいろいろと思考錯誤しましたが、結局SetLengthをしなければ
  DLLを読む事が出来ない事は確かです。


えーと  2005-10-04 01:08:20  No: 17860

Data := '';


えーと  2005-10-04 01:20:21  No: 17861

string + SetLength() をメモリバッファとして使ってるかぎり、
メモリについて心配する必要はないです。

普通は

PChar + GetMem() + FreeMem() を使います。


むく  2005-10-04 01:22:06  No: 17862

えーとさん。
  もちろん、一番最初にやりました。
  が、メモリは増える一方なのです。
  ヘルプを見る限り、SetLengthはその領域のメモリーを確保すると
  なっており、その廃棄方法が書いていないので困っています。
  空白の代入では廃棄されないようです。


えーと  2005-10-04 01:28:01  No: 17863

気にする必要はないです。


えーと  2005-10-04 01:35:37  No: 17864

> その廃棄方法が書いていないので困っています。

参照数がゼロの長い文字列がいつガベージコレクトされるかなんて、誰にも
わかりません。気にするんでしたら、前に書きましたように文字列をバッファ
にするのをやめて

PChar + GetMem() + FreeMem() 

を使ってください。


シャチ  2005-10-04 01:42:58  No: 17865

むくさん、こんにちは。

むくさんのコードですが、ローカル変数Dataのポインタを
Resultに代入していますよね?
これはちょっとおかしくはないですか?


むく  2005-10-04 01:47:14  No: 17866

えーとさん。
  気にする必要なければ困らないんですが。
  現実にメモリーが増えてしまいメモリーオーバーで処理が止まるので。
  
  PChar + GetMem() + FreeMem() は一番初めにやりました。
  これが出来れば苦労しないんですよね〜。
  Dllに対してはString型をSetLengthして渡すしか方法が無く
  困っています。


むく  2005-10-04 01:58:05  No: 17867

シャチさん。
  dataには2048のうちでどこまでデータが入っているか決まってないので
  このようにしてますが、おかしいでしょうか?
  ひょっとしてこれが原因と言うことですか?
  ちょっと考えてみます。


逆は真  2005-10-04 02:05:38  No: 17868

DLL側で戻り値のためのメモリを確保するのではなく、呼び出し側でメモリを確保してから、そのアドレスをPCharでDLLに渡すべきでは?


むく  2005-10-04 02:09:56  No: 17869

逆は真さん。  
  DLL側がString型のポインター以外受付けないんです。  
  DLL作成者の意図が不明なのでなぜかは答えられませんが。
  Pcharのアドレスを渡すにしても、一度String型をSetLengthし
  Pcharにキャストする事になり、結果は何もかわらないんです。


篠田雅夫  2005-10-04 02:16:45  No: 17870

procedure  foo;
var
 Data: array of char;
begin
〜  略  〜
 SetLength(data,2048);
 Dll処理(@Data);
 result := PChar(Data);
〜  略  〜
end;

のようにDataが動的配列ならばDataを開放する場合Data:=nil;ですが、そのほか明示的にFinalizeを使う手もあります。しかし、この関数の中で破棄するわけではないようですね。


篠田雅夫  2005-10-04 02:19:02  No: 17871

それから
> result := PChar(Data);
はresult := PChar(@Data[0]);ですよね


にしの  2005-10-04 02:40:03  No: 17872

DLL側の関数の引数にStringがあるんですか?
であれば、
ShareMemユニットとBORLNDMM.DLLを利用する必要があるのでは?
これらを使ってもなお、メモリリークしているのでしょうか。


シャチ  2005-10-04 03:40:54  No: 17873

> dataには2048のうちでどこまでデータが入っているか決まってないので
> このようにしてますが、
SetLength手続きは新しく割り当てられた空間を初期化しませんから、
変数をDLLに渡す前にFillCharでゼロクリアしておくとよいと思います。
結果が返ってきたらStrLenで長さを取得できます。

> おかしいでしょうか?
result := PChar(data);
この瞬間に参照カウントが増えるんじゃないでしょうか?
参照カウントが増えればDataは破棄されなくなるのでは?


えーと  2005-10-04 03:52:38  No: 17874

結局その DLL のインポート部分を見てみないとなんともいえませんね。
その DLL 内でリークってことはないですよね?
インタフェースの部分でしたらどうにでもなります。

> DLL側がString型のポインター以外受付けないんです。

これが意味不明です。PString ってことなら、変な DLL ですね。
もし、PChar であって、それが GetMem() したものを受け付けないとすると、
DLL として変です。


むく  2005-10-04 20:41:22  No: 17875

書込み頂いた皆様。

>これが意味不明です。PString ってことなら、変な DLL ですね。
>もし、PChar であって、それが GetMem() したものを受け付けないとすると、
>DLL として変です。
ごもっともです。DLLの間違いと言うかDLLがいけないんじゃないかと
感じています。ですが、これしか方法がないのでどうにかするしかない
のかと思ってあきらめてます。

いろいろなご意見を頂いていろいろと試していますがなかなかうまく
いきません。
Pcharのポインタ型で引数を指定すればStringにこだわる事はなくなった
のですが、FreeMemしてもまだどこかでリークしてしまいます。

多分詳細なコードを見てもらわない限り判断が難しい所まできてしまって
いるよなので、未解決ですが身を引きます。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加