• ベストアンサー

メモリ解放の仕方を教えてください

下記のコードでプロセスの使用メモリ容量をみると、同じデータが2つメモリ上存在しているのですが、 この両方ともメモリ解放をするにはどうすればいいのでしょうか?最後のfreeでエラーが出てしまいます。 完全な解放の仕方を教えてください。お願いします。 HANDLE m_hHeap; LPSTR m_pData; LPVOID pMem1 m_hHeap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0); m_pData = (LPSTR)HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, nDataSize); memcpy(pMem1, m_pData, size1); HeapFree(m_hHeap, HEAP_ZERO_MEMORY, m_pData); free(pMem1);

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.7

メモリの確保、開放に関しては、何の問題もない。 メモリが20Mバイトづつ減るのは、セカンダリサウンドバッファを開放せずに何度も作成するのが原因。 セカンダリサウンドバッファは「音源の数だけ、何個も作る事が出来る」ので、解放せずに作成を繰り返せば、何個も出来上がってしまうのは当然。 ダイレクトサウンドでサウンドバッファを作成させると、デバイスオブジェクトは内部的にメモリ確保を行います。 ここで確保されたメモリは、不要になった場合はRelease()メソッドで解放する必要があります。 これら、ダイレクトサウンドデバイスオブジェクトが所有する内部メモリは、デバイスオブジェクト(ソース上でlpDS)を開放する事により、自動的に行われます。 以下の点に注意(基本的な注意事項なんだけど)して「何度も実行しない」ようにして下さい。 ・デバイスオブジェクト(ソース上でlpDS)は、1度だけ作成する。再作成する(DirectSoundCreate8を呼び直す)前には、必ずRelease()メソッドで解放すること。 ・プライマリサウンドバッファは、1度だけ作成する。再作成する(lpDS->CreateSoundBufferを呼び直す)前には、必ずRelease()メソッドで解放すること。 ・セカンダリサウンドバッファは、作成すると作成した回数だけ個別に作成される。再作成する(lpDS->CreateSoundBufferを呼び直す)前には、必ずRelease()メソッドで解放すること。また、不要になった場合は、必ずRelease()メソッドで解放すること。 再生ストップ関数の中で「ダイレクトサウンドは、後でもう一度作り直すから、全部解放したい」というなら // .h//////////// LPDIRECTSOUND8 ds; //追加 LPDIRECTSOUNDBUFFER dsp; //追加 LPDIRECTSOUNDBUFFER dsb; // .ccp//////////// (中略) // mainの冒頭など、最初に一度だけ通過する場所に ds=NULL; dsb=NULL; dsp=NULL; // を追加。 (中略) // ここから再生ストップ関数 ////////////////////// if(dsb != NULL){ dsb->Stop(); dsb->Release(); //追加 dsp=NULL; //追加 } if(dsp != NULL){ //追加 dsp->Release(); //追加 dsp=NULL; //追加 } //追加 if(ds != NULL){ //追加 ds->Release(); //追加 ds=NULL; //追加 } //追加 HeapFree(m_hHeap, HEAP_ZERO_MEMORY, m_pWaveFormat); HeapFree(m_hHeap, HEAP_ZERO_MEMORY, m_pData); というように「必ず解放」すること。 それと、ds、dsp、dsbは、必ず「起動後に1度だけ通る場所でNULLに初期化」しておくこと。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (7)

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.8

追記。 うっかり、投稿した「修正ソースコード」の中に、1文字だけ「タイプミス」した箇所がありました。 「どこを間違えてタイプミスしたか?」を探せば、ソースコードについての理解が深まるので、質問者さんで「ミスした場所」を探して、ご自分で修正してみて下さい。

sonar_fisx
質問者

お礼

ありがとうございます。 うまくいきました。何度繰り返してもメモリの蓄積は起きなくなりました。 memcpyの行でメモリが増えたのでDirectSoundは関係ないと決めつけてしまいました。 DirectSoundの事まで詳しく教えていただき、本当にありがとうございました!

全文を見る
すると、全ての回答が全文表示されます。
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.6

コードと現象からすると、HeapDestroy()をしていないのでメモリが回収されないまま次のヒープ作成→メモリ確保で次々と増えていっているように思えます。

sonar_fisx
質問者

お礼

ありがとうございました。後出ししてしまったDirectSoundがすべての原因でした。 タイトル上のHeap関連の質問の回答、完璧でした。勉強になりました。 私が、memcpyのせいだと言い張ったのが間違いでした。 長々と一緒に考えて下さり、ありがとうございました。

sonar_fisx
質問者

補足

HeapDestroy()はしてませんでした。 CreateHeapをクラスのInit部分に持っていきました。 しかし、やはりmemcpyでコピーされたpMem1が解放できません。 memcpyは指定したポインタを先頭としてデータを丸ごとコピーする、で解釈はあってるのでしょうか? free(pMem1);が失敗するのは、型がLPVOIDで、もしかしてサイズがわからないからでしょうか? freeが通るように書き換えることはできませんか?

全文を見る
すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.5

「このHeapAlloc関連の処理をするたびに20MBのデータが残ってしまってどんどん増えていきアプリ自体を終了するまで減らない」というのは, Lock/Unlock をするたびに 20MB ずつプロセスの使用メモリが増えるということですか?

sonar_fisx
質問者

補足

違います。一行づつじっくりメモリを監視しているのですが、Lock/Unlockでは増減しません。 HeapAllocで領域確保したm_pDataはHeapFreeでエラー無く解放できています。この部分はこれで完結できていると思うんです。 あとはmemcpyの行で増えた20MBが不明で、再生停止を繰り返すたびにmemcpyの行で増えた20MBが蓄積されていくんです。

全文を見る
すると、全ての回答が全文表示されます。
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.4

Lock()/Unlock()が何やってるAPIなのかは調べられませんでしたが、それはさておきalloc()していないメモリは当然free()できません。 また、プログラム上で解放したメモリが実際にいつ回収されるかはOS任せであり、解放したからといって必ずしも即座に反映される訳ではありません。

sonar_fisx
質問者

補足

このHeapAlloc関連の処理をするたびに20MBのデータが残ってしまってどんどん増えていきアプリ自体を終了するまで減らないんです。 下に張ったコードですが、コピー先のデータを使って再生をしているのではないかと思うんです。 allocしてないデータの消滅にはポインタを消滅させるしかないということでしょうか?やり方もわからないです。

全文を見る
すると、全ての回答が全文表示されます。
  • titokani
  • ベストアンサー率19% (341/1726)
回答No.3

Lock,Unlockというのは、自作関数でしょうか? ソースコードはわかりますか?

sonar_fisx
質問者

補足

IDirectSoundBuffer8::Lockです。 そのまま貼ってしまってすいません。 // .h//////////// LPDIRECTSOUNDBUFFER dsb; LPBYTE m_pWaveFormat; // ファイルから読み取られたフォーマットデータが入るバッファのアドレス WORD wChannels; //フォーマットチャンネルデータ格納 DWORD nSmplPerSec; //フォーマット周波数データ格納 //__int16* data; //サウンドデータ格納 HANDLE m_hHeap; LPSTR m_pData; // ファイルから読み取られたサウンドデータが入るバッファのアドレス DWORD wdSize; //サウンドデータサイズ格納 LPVOID pMem1,pMem2; // .ccp//////////// LPDIRECTSOUND8 lpDS = NULL; LPDIRECTSOUNDBUFFER lpDSP = NULL; LPDIRECTSOUNDBUFFER lpDSB = NULL; if ( FAILED( DirectSoundCreate8(NULL, &lpDS, NULL) ) ){ AfxMessageBox(_T("FAILED DirectSoundCreate8")); } if (FAILED(lpDS->SetCooperativeLevel(m_hWnd, DSSCL_PRIORITY))) { AfxMessageBox(_T("FAILED SetCooperativeLevel")); } //__int16 *buf; DWORD size1,size2; DWORD readsize; readsize = wdSize; DSBUFFERDESC desc; //プライマリサウンドバッファ作成 ZeroMemory(&desc, sizeof(DSBUFFERDESC)); desc.dwSize = sizeof(DSBUFFERDESC); desc.dwFlags = DSBCAPS_PRIMARYBUFFER; if (FAILED(lpDS->CreateSoundBuffer(&desc, &lpDSP, NULL))) { AfxMessageBox(_T("FAILED CreateSoundBuffer_P")); } //セカンダリサウンドバッファ作成 ZeroMemory(&desc, sizeof(DSBUFFERDESC)); desc.dwSize = sizeof(DSBUFFERDESC); desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCDEFER | DSBCAPS_CTRLVOLUME; desc.dwBufferBytes = readsize; WAVEFORMATEX FEX; ZeroMemory(&FEX, sizeof(WAVEFORMATEX)); FEX.wFormatTag = WAVE_FORMAT_PCM; FEX.nChannels = wChannels; FEX.nSamplesPerSec = nSmplPerSec; FEX.wBitsPerSample = 16; FEX.nBlockAlign = ((FEX.nChannels * FEX.wBitsPerSample) / 8); FEX.nAvgBytesPerSec = (FEX.nSamplesPerSec * FEX.nBlockAlign); FEX.cbSize = 0; desc.lpwfxFormat = &FEX; if (FAILED(lpDS->CreateSoundBuffer(&desc, &lpDSB, NULL))){ AfxMessageBox(_T("FAILED CreateSoundBuffer_S")); } if(FAILED(lpDSB->Lock(0, readsize, &pMem1, &size1, &pMem2, &size2, 0))){ AfxMessageBox(_T("FAILED Lock")); } memcpy(pMem1, m_pData, size1); if (size2){ memcpy(pMem2, m_pData + size1, size2); } lpDSB->Unlock(pMem1, size1, pMem2, size2); lpDSB->Play(0, 0, 0); dsb = lpDSB; // ここから再生ストップ関数 ////////////////////// if(dsb != NULL){ dsb->Stop(); } //free(pMem1); HeapFree(m_hHeap, HEAP_ZERO_MEMORY, m_pWaveFormat); HeapFree(m_hHeap, HEAP_ZERO_MEMORY, m_pData); //free(pMem2);

全文を見る
すると、全ての回答が全文表示されます。
  • php504
  • ベストアンサー率42% (926/2160)
回答No.2

Lock( )でメモリ確保されてUnlock( )で開放されていると推測されます。 free( )する必要はありません。

sonar_fisx
質問者

補足

データは20MBなのですが、HeapAllocの行でプロセスのメモリ使用量が20MB増えて、 memcpyの行でもう20MB増え、HeapFreeの行で20MB減って残りの20MBが不明です。 Unlockの行ではメモリが減らないんです。

全文を見る
すると、全ての回答が全文表示されます。
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.1

pMem1の領域はどこでどうやって確保していますか。

sonar_fisx
質問者

補足

変数の宣言を.hでしています。領域の確保がわかりません。 Lock(0, readsize, &pMem1, &size1, &pMem2, &size2, 0) Unlock(pMem1, size1, pMem2, size2) これを宣言と解放の間に通してます。ここで領域の確保がされているのでしょうか? これ以外でpMen1がかかわっているコードはありません。自分でHeapAllocはしていません。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 多次元配列を動的に取る方法で悩んでいます。

    現在、以下のコードで三次元配列を動的に取る方法を作成しています。 { int i,j; char ***Regdata; LPVOID heapAdr; Regdata = (char ***)HeapAlloc(GetProcessHeap(),HEAP_NO_SERIALIZE,sizeof(char) * 1000); for(i=0;i<=1000;i++){ heapAdr = HeapAlloc(GetProcessHeap(), //ここでエラーが発生します。 HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, sizeof(char) * 6); if(heapAdr != NULL) { Regdata[i] = (char **)heapAdr; for(j=0;j<=6;j++){ heapAdr = HeapAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, sizeof(char) * STRING_LENGTH); if(heapAdr != NULL) { Regdata[i][j] = (char *)heapAdr; } else { break; } } } else { break; } } } この方法だと、約40~50回ループした時点でHeapAlloc関数のところで 実行時エラーが発生してしまいます。 GetLastError関数を用いてエラーメッセージを取得したところ、 「No 998:メモリの場所に無効なアクセスがありました。」 というメッセージが返ってきました。 現状、どうしたらよいのかわからない状態です。 ご存知の方がいらっしゃれば、お教えいただきたいです。 以上、宜しくお願いします。

  • メモリの解放free()について

    メモリ解放についての質問です。 下の関数をループで呼び出すとき、new_itemのメモリ解放free()はどのように行えば良いでしょうか? typedef struct _ITEM { int n,m; void *right; } item; int data() { int i,j,k; int n,m; item *new_item,*last_item; for (i = 0; i <= M-1; i++) { ... last_item = &(list[i]); k = 0; for (j = 0; j <= num-1; j++) { /* making new item */ if ((new_item = (item*)malloc(sizeof(item))) == NULL) { fprintf(stderr,"Can't allocate memory.\n"); exit(-1); } new_item->m = i; new_item->n = k; new_item->right = NULL; last_item->right = new_item; last_item = new_item; } } }

  • Linuxのメモリの関して

    質問1: freeというコマンドで見たところ、freeが少ないで、大半がcachedとして 使われているそうです。 このcachedに使われたメモリはどんなコマンドで解放することできるでしょうか? 質問2: topというコマンドで見たところ、httpdというプロセスが沢山のメモリ使っている(ひとつのhttpdプロセスは140MBぐらい)そうです、このhttpdはApacheのプロセスで、どうしてこんなに沢山メモリ使うでしょうか? 以上、どうぞよろしくお願いします。

  • メモリの解放free

    double **w; int no;    | if((w = (double *)malloc(sizeof(double)*no))==NULL){ printf("Memory Error1"); exit(1); }    |  データ格納処理    | free(w); のようなプログラムの中で、 データ格納処理の途中でSegmentation faultで 落ちてしまいました。この場合、freeが実行されなくても メモリは解放してくれるのでしょうか? また、mallocでメモリ確保できたはずなのに 存在するはずの場所にデータを格納できない原因として 考えられるものはなんでしょうか? ちなみに、落ちる場所が実行の度に変わっているようで、 同じ条件なのにデータの格納数が違っています。

  • メモリー内を解放するフリーソフトの最も信頼性の高いものを使いたいのですが、お薦めは?

    過去の回答の中に、 『メモリー内を解放する為にフリーソフトでは、ビーメム、メモリークリーナーなど多数有る』 との記述(概略)があります。私は今回初めてメモリ内の解放なるものをしたいと思っているのでご教授願えませんか? メモリー内を解放するフリーソフトの最も信頼性の高いものを使いたいのですが、お薦めはどんなものでしょうか?実はちょっと怖い気がしていますので。宜しくお願いします。

  • HeapReAllocについて

    HeapReAllocについて質問いたします VC++5.0 & SDK で作成しています 以下のようにメモリを確保し、その後メモリの移動が起こらないように HEAP_REALLOC_IN_PLACE_ONLYを指定してHeapReAllocしています 必ず決まった回数でHeapReAllocが失敗してしまいます やはり下のようにリサイズに失敗したら新たに領域を確保し それまでのデータをコピーするのが普通なのでしょうか? ただ単にメモリを移動せずに取れるだけの領域がなくて失敗しているだけならば いいのですが、それほど大きいサイズでもないし、根本的に間違っているなら 解決にならないと思いまして質問させていただきます よろしくお願いいたします time_t *endtime; time_t *tmptime; if ((endtime = (time_t *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(time_t) * tile_cnt)) == NULL) {  return 0; } while( tile_cnt < 30 ){  tile_cnt++;  // リサイズ  if((tmptime = (time_t *)HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, endtime,                        tile_cnt*sizeof(time_t))) == NULL){   // サイズ拡大できなかったので再度そのサイズで領域確保   if ((tmptime = (time_t *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(time_t) * tile_cnt))                        == NULL) {    HeapFree(GetProcessHeap(), 0, endtime);    return 0;   } else {    // 新しく領域を確保したので今までのデータをコピー    CopyMemory(tmptime, endtime, sizeof(time_t)*(tile_cnt-1));    // 元の領域を開放    HeapFree(GetProcessHeap(), 0, endtime);    endtime = tmptime;   }  } else {   endtime = tmptime;  } } //解放 HeapFree(GetProcessHeap(), 0, endtime);

  • ヒープメモリの解放について

    すみません教えてください。 VCを始めたばかりで、メモリ等の事が良くわかりません。 (2)で、Invalid Address specified to RtlValidateHeap( 340000, 344978 )やHEAP: Free Heap block 344970 modified at 344998 after it was freed のメモリエラーが出力されます。 調べてみると(1)で解放されていないのですが、delete pBufが処理されていないと思います。 記述等に問題があるのでしょうか? 調べてみると問題ないように思えるのですが・・・ ご存知の方教えてください。 <ソース> HANDLE hEventLog = NULL; EVENTLOGRECORD *pBuf = NULL; /* イベントログのオープン処理 */ : : : /* イベントログの最大数 */ bResult = GetNumberOfEventLogRecords(hEventLog, &EventNum); //最大サイズを取得 BufSize = 1; pBuf = new EVENTLOGRECORD; bResult = ::ReadEventLog(hEventLog,EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ,0,pBuf,BufSize,&ReadBytes,&NextSize); if(!bResult && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {  eMsg = "ファイルリードエラー2" ;  CloseEventLog(hEventLog);  delete pBuf;  return -1; } delete pBuf; --->(1)メモリが解放されない。 BufSize = NextSize; bResult = ::ReadEventLog(hEventLog,EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ,0,pBuf,BufSize,&ReadBytes,&NextSize); if(!bResult && GetLastError() != ERROR_INSUFFICIENT_BUFFER){  eMsg = "ファイルリードエラー3";  CloseEventLog(hEventLog);  delete pBuf;  return -1;  } } delete pBuf; --->(2)ここでエラー

  • メモリ不足

    起動時の空きメモリは1300mb位あるのですが、起動後7分で50mbになってしまいます。そしてメモリ不足ですとのメッセージが時々現れて作業ができなくなります。 タスクマネージャーのパーフォーマンスタブに表示されている情報を書きますと、次のような感じです。 物理メモリ(MB) 合計         3261 キャッシュ済み   2165 空きメモリ         3 システム    ハンドル 19745 スレッド 836 プロセス 82 起動時間 ページファイル 1366m/8088m OSはVISTAです。 メモリ不足解消方法をご存知の方教えてください。

  • メモリをフルに使っていない?

    似たような質問がみつけられなかったので、質問させていただきます。 フリーソフトのMCleanを使っているのですが、そのモニターを見ているとCPUは100%まで使われているのですが、メモリーは512Mのうち300前後で頭打ちとなっています。これはどう解釈するのでしょうか? 動作が若干遅いのですが、それはメモリをフルに使えていないからなのでしょうか? メモリをフルに使うように設定することはできるのでしょうか? よろしくお願い致します。 CPUは mobile AMD Athlon(tm) XP 1800+ 1.53GHz メモリは512MB RAM です。

  • メモリの使用量について

    メモリの使用量の確認方法について教えてください。 freeコマンドを実行すると以下のように表示され、2GB中1.3GBを使用していることが分かります。 total used free shared buffers cached Mem: 2072828 1358364 714464 0 175372 836028 -/+ buffers/cache:346964 1725864 Swap:2096472 0 2096472 どのプロセスがメモリを消費しているか調べたいと思い、topコマンドを実行後、"M"でメモリの消費量の多い順にプロセスを並べ替えて、使用率の合計を計算してみました。 しかし、その合計値は約20%ほどです。 2GBのメモリを積んでいますので400MBほどしか使用していないことになります。 freeコマンドとtopコマンドでどうしてこんなに大きな差が出ているのでしょうか? また、どちらが正しい値なのでしょうか? ご存知の方がいらっしゃいましたら教えてください。 よろしくお願いいたします。