- ベストアンサー
メモリ解放の仕方を教えてください
下記のコードでプロセスの使用メモリ容量をみると、同じデータが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);
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
メモリの確保、開放に関しては、何の問題もない。 メモリが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)
追記。 うっかり、投稿した「修正ソースコード」の中に、1文字だけ「タイプミス」した箇所がありました。 「どこを間違えてタイプミスしたか?」を探せば、ソースコードについての理解が深まるので、質問者さんで「ミスした場所」を探して、ご自分で修正してみて下さい。
- D-Matsu
- ベストアンサー率45% (1080/2394)
コードと現象からすると、HeapDestroy()をしていないのでメモリが回収されないまま次のヒープ作成→メモリ確保で次々と増えていっているように思えます。
お礼
ありがとうございました。後出ししてしまったDirectSoundがすべての原因でした。 タイトル上のHeap関連の質問の回答、完璧でした。勉強になりました。 私が、memcpyのせいだと言い張ったのが間違いでした。 長々と一緒に考えて下さり、ありがとうございました。
補足
HeapDestroy()はしてませんでした。 CreateHeapをクラスのInit部分に持っていきました。 しかし、やはりmemcpyでコピーされたpMem1が解放できません。 memcpyは指定したポインタを先頭としてデータを丸ごとコピーする、で解釈はあってるのでしょうか? free(pMem1);が失敗するのは、型がLPVOIDで、もしかしてサイズがわからないからでしょうか? freeが通るように書き換えることはできませんか?
- Tacosan
- ベストアンサー率23% (3656/15482)
「このHeapAlloc関連の処理をするたびに20MBのデータが残ってしまってどんどん増えていきアプリ自体を終了するまで減らない」というのは, Lock/Unlock をするたびに 20MB ずつプロセスの使用メモリが増えるということですか?
補足
違います。一行づつじっくりメモリを監視しているのですが、Lock/Unlockでは増減しません。 HeapAllocで領域確保したm_pDataはHeapFreeでエラー無く解放できています。この部分はこれで完結できていると思うんです。 あとはmemcpyの行で増えた20MBが不明で、再生停止を繰り返すたびにmemcpyの行で増えた20MBが蓄積されていくんです。
- D-Matsu
- ベストアンサー率45% (1080/2394)
Lock()/Unlock()が何やってるAPIなのかは調べられませんでしたが、それはさておきalloc()していないメモリは当然free()できません。 また、プログラム上で解放したメモリが実際にいつ回収されるかはOS任せであり、解放したからといって必ずしも即座に反映される訳ではありません。
補足
このHeapAlloc関連の処理をするたびに20MBのデータが残ってしまってどんどん増えていきアプリ自体を終了するまで減らないんです。 下に張ったコードですが、コピー先のデータを使って再生をしているのではないかと思うんです。 allocしてないデータの消滅にはポインタを消滅させるしかないということでしょうか?やり方もわからないです。
- titokani
- ベストアンサー率19% (341/1726)
Lock,Unlockというのは、自作関数でしょうか? ソースコードはわかりますか?
補足
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)
Lock( )でメモリ確保されてUnlock( )で開放されていると推測されます。 free( )する必要はありません。
補足
データは20MBなのですが、HeapAllocの行でプロセスのメモリ使用量が20MB増えて、 memcpyの行でもう20MB増え、HeapFreeの行で20MB減って残りの20MBが不明です。 Unlockの行ではメモリが減らないんです。
- D-Matsu
- ベストアンサー率45% (1080/2394)
pMem1の領域はどこでどうやって確保していますか。
補足
変数の宣言を.hでしています。領域の確保がわかりません。 Lock(0, readsize, &pMem1, &size1, &pMem2, &size2, 0) Unlock(pMem1, size1, pMem2, size2) これを宣言と解放の間に通してます。ここで領域の確保がされているのでしょうか? これ以外でpMen1がかかわっているコードはありません。自分でHeapAllocはしていません。
お礼
ありがとうございます。 うまくいきました。何度繰り返してもメモリの蓄積は起きなくなりました。 memcpyの行でメモリが増えたのでDirectSoundは関係ないと決めつけてしまいました。 DirectSoundの事まで詳しく教えていただき、本当にありがとうございました!