ab.com コミュニティ https://www.activebasic.com/forum/ |
|
メモリ解放時のエラー https://www.activebasic.com/forum/viewtopic.php?t=2451 |
ページ 1 / 1 |
作成者: | Z [ 2008年8月07日(木) 17:06 ] |
記事の件名: | メモリ解放時のエラー |
waveoutをつかった音合成のプログラムを作っているのですが debugするとメモリ解放時に HEAP[wavelast_debug.exe]: Heap block at 00191D30 modified at 0019C97C past requested size of ac44 スレッド(&HDE0)のブレーク ポイント(EPI=&H77F75554)。 HEAP[wavelast_debug.exe]: Invalid Address specified to RtlFreeHeap( 00140000, 00191D38 ) スレッド(&HDE0)のブレーク ポイント(EPI=&H77F75554)。 というエラーが出ます。これってメモリのエラーですよね? (経験上そう思う) ところが実際にコンパイルしてみると正常に動作します。 しかしエラーが出る以上はやはり問題があると思います。 メモリ上のエラーは致命的なので何とかしたいです。 実はメモリやwaveoutはあまり知らないので 勉強しながらやっている状態です。 ソースをさらしたいのですが超ロングぐだぐだクソースなため 見せるに忍びないので重要そうな部分をさらします。 メモリ確保から演奏開始まで コード: ZeroMemory(VarPtr(pwh),sizeof(WAVEHDR)) pwh.lpData=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,SRATE)'SRATEは曲の長さ For i=0 TO SRATE pwh.lpData(i)=(i番目のデータ)←省略している Next pwh.dwBufferLength=SRATE pwh.dwFlags=WHDR_BEGINLOOP or WHDR_ENDLOOP pwh.dwLoops=1 waveOutPrepareHeader(hwo,pwh,sizeof(WAVEHDR)) waveOutWrite(hwo,pwh,sizeof(WAVEHDR))で問題となる終了時はコールバックにて コード: Function MainWndProc(hWnd As DWord, dwMsg As DWord, wParam As DWord, lParam As DWord) As DWord ' TODO: この位置にウィンドウメッセージを処理するためのコードを記述します。 Select Case dwMsg case MM_WOM_DONE waveOutUnprepareHeader(hWaveOut,pwh,sizeof(WAVEHDR)) HeapFree(GetProcessHeap(),0,pwh.lpData)←ここでエラーが出るwaveoutではwaveOutUnprepareHeaderとHeapFreeは プログラム終了時だけではなく、演奏終了時にやらないと メモリ使用量が上昇してしまうので抜け目なくやっているつもりです。 実際メモリ使用量も上がったり下がったりで困っています。 ・・・どうでも良いですが実はVer2.0辺りからABをやっていて 掲示板にもちょくちょく顔を出していたのですが、いつの間にか行かなくなり ABもVer3.0~4.0初期しか使用しておらず、最近来て見たら Ver5.0とかの話になってて時代の流れを感じました。 |
作成者: | tak [ 2008年8月07日(木) 21:50 ] |
記事の件名: | Re: メモリ解放時のエラー |
引用: HEAP[wavelast_debug.exe]: Heap block at 00191D30 modified at 0019C97C past requested size of ac44
この警告メッセージは、HeapAlloc() で確保した領域の外にまで値を書き込んでしまったときのものです。スレッド(&HDE0)のブレーク ポイント(EPI=&H77F75554)。 HEAP[wavelast_debug.exe]: Invalid Address specified to RtlFreeHeap( 00140000, 00191D38 ) スレッド(&HDE0)のブレーク ポイント(EPI=&H77F75554)。 プログラムが debug 版なら、メモリ解放時に領域周辺が汚されていないかチェックして、もし汚れていたらこのような警告を吐いてブレークします。 この手のバグは見つけ出すのが難しいことも多いですが・・・ とりあえず、その領域に書き込むコードを重点的に調べてみてください。 たとえば、書き込む前にそのポインタが正しく領域内を指しているか逐一チェックするなど。 # そういえば Assert ってないんですかね。 |
作成者: | Z [ 2008年8月09日(土) 13:04 ] |
記事の件名: | 返信ありがとうございます。 |
返信ありがとうございます。 いろいろやっていたので返事が遅れてしまってすいません。 書き込み時に間違いがある、とのことでしたので、 書き込みの部分を調べてみました。 といっても書き込みを行う部分は前回投稿した部分のみなので その辺で試したのですが、 コード: ZeroMemory(VarPtr(pwh),sizeof(WAVEHDR)) pwh.lpData=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,SRATE)'SRATEは曲の長さ ’ここをAとして For i=0 TO SRATE pwh.lpData(i)=(i番目のデータ)←省略している Next ’ここをBとする。 pwh.dwBufferLength=SRATE pwh.dwFlags=WHDR_BEGINLOOP or WHDR_ENDLOOP pwh.dwLoops=1 waveOutPrepareHeader(hwo,pwh,sizeof(WAVEHDR)) waveOutWrite(hwo,pwh,sizeof(WAVEHDR))上のコードでAの部分でメモリの解放を行ったところ問題はなく、 Bで解放したところ例のエラーが出ました。 つまり書き込みのこの部分に問題があったとわかりました。 コード: For i=0 TO SRATE pwh.lpData(i)=(i番目のデータ)←省略している Nextそうなると怪しいのが省略してしまった部分なのですが、よく見ると 型を間違えてました(オイ)。ポインタと値がごっちゃになってましたので修復しました。 しかしどういうわけかこれでも改善がされません。 実際のところエラーが発生する回数は減ったのですが、 稀にエラーが出ています。 回数が少なくなったのは良いですがデバッグがしずらいです。 省略部分は音の合成の部分なのですがやはり省略した部分が 悪いのでしょうか?といってもソースを曝さなきゃわかりませんが カオス過ぎて時間がかかりそうなのでとりあえず現状を報告しました。 |
作成者: | konisi [ 2008年8月09日(土) 14:15 ] |
記事の件名: | |
コード: For i=0 TO SRATE pwh.lpData(i)=(i番目のデータ)←省略している Nextを コード: For i=0 TO SRATE-1 pwh.lpData(i)=(i番目のデータ)←省略している Nextにしてみたらどうなりますか? |
作成者: | Z [ 2008年8月09日(土) 22:13 ] |
記事の件名: | すぐに出来るのでやってみましたが・・・ |
ちょっとした改良なので即実行してみましたが 同様のエラーが出てしまいました。 似たような考えで確保する領域を増やす方法も考えたのですが だめでした。 コード: ZeroMemory(VarPtr(pwh),sizeof(WAVEHDR)) pwh.lpData=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,SRATE)'SRATEは曲の長さ For i=0 TO SRATE-1 pwh.lpData(i)=(i番目のデータ)←省略している Next pwh.dwBufferLength=SRATE pwh.dwFlags=WHDR_BEGINLOOP or WHDR_ENDLOOP pwh.dwLoops=1 waveOutPrepareHeader(hwo,pwh,sizeof(WAVEHDR)) waveOutWrite(hwo,pwh,sizeof(WAVEHDR))それとやってて気づいたのですがwaveOutUnprepareHeaderのときにも エラーが出るようです。こちらのエラーのほうが頻度が低いです。 コード: Function MainWndProc(hWnd As DWord, dwMsg As DWord, wParam As DWord, lParam As DWord) As DWord ' TODO: この位置にウィンドウメッセージを処理するためのコードを記述します。 Select Case dwMsg case MM_WOM_DONE waveOutUnprepareHeader(hWaveOut,pwh,sizeof(WAVEHDR)))←ここでもエラーが出る HeapFree(GetProcessHeap(),0,pwh.lpData)←ここでエラーが出るでそのときのエラーメッセージは 「スレッド(&HAC8)でアクセス違反がありました(EPI=&H76AF1F22)。」 というような感じになっています。 |
作成者: | Z [ 2008年8月09日(土) 23:19 ] |
記事の件名: | 書き忘れ |
書き忘れましたが、 SRATE-1(もしくは確保領域を増やす)をするとエラー頻度は確実に減ります。 しかし100%ではありません。 というかムリだったらもうこれでもいいかな、なんて思ってきました。 |
作成者: | Z [ 2008年8月09日(土) 23:47 ] |
記事の件名: | 過去ログで気づいた |
過去ログに似たようなものを発見したのですが 引用:
> ヒープ領域に対してメモリを確保(HeapAlloc,HeapReAlloc)した場合、
とまけイヌさんが書いていました。(そういえばこの名を聞くのも久しぶりダ・・・)> 実は確保したメモリ以上にデータを扱う事ができます。 > これは確保されたヒープハンドルがハンドルに過ぎないためであり、 > たまたま未確保の領域を侵しても実害が無かっただけに過ぎません。 > > しかし、幾ら実害が無くても確保したヒープ領域を開放(HeapFree)すると、 > 確保した領域外のデータまでクリアしてしまうみたいで > 初めてエラーが発覚したりします。 > > この辺はABというよりAPIの問題になってきますので、 > 一度MSDN等を参照されることをお勧めします。 > > http://www.microsoft.com/japan/msdn/ takさんが言っていることと本質的には変わりないのですが、 なんか結構面倒そうになってきた。 |
作成者: | konisi [ 2008年8月10日(日) 00:41 ] |
記事の件名: | |
試しに適当に作ってみたのですが、特にエラーは出ないようです。 [ここをクリックすると内容が表示されます]
コード: Type WAVEFORMATEX wFormatTag As Word nChannels As Word nSamplesPerSec As DWord nAvgBytesPerSec As DWord nBlockAlign As Word wBitsPerSample As Word cbSize As Word End Type Type WAVEHDR lpData As *Byte dwBufferLength As DWord dwBytesRecorded As DWord dwUser As *DWord dwFlags As DWord dwLoops As DWord lpNext As *WAVEHDR reserved As *DWord End Type Const WHDR_DONE = 1 Const WHDR_PREPARED = 2 Const WHDR_BEGINLOOP = 4 Const WHDR_ENDLOOP = 8 Const WHDR_INQUEUE = 16 Const CALLBACK_FUNCTION = &H30000 Const CALLBACK_NULL = 0 Const CALLBACK_WINDOW = &H10000 Const WAVE_FORMAT_PCM=1 Const WAVE_MAPPER = -1 TypeDef MMRESULT = Long TypeDef HWAVEOUT = HANDLE TypeDef LPHWAVEOUT = *HWAVEOUT TypeDef LPWAVEHDR = *WAVEHDR TypeDef LPWAVEFORMATEX = *WAVEFORMATEX Declare Function waveOutOpen Lib "winmm" (phwo As LPHWAVEOUT,uDeviceID As DWord,pwfx As LPWAVEFORMATEX,dwCallBack As VoidPtr,dwCallBackInstance As DWord,fdwOpen As DWord) As MMRESULT Declare Function waveOutPrepareHeader Lib "winmm" (who As HWAVEOUT,pwh As LPWAVEHDR,cbwh As DWord) As MMRESULT Declare Function waveOutWrite Lib "winmm" (hwo As HWAVEOUT,pwh As LPWAVEHDR,cbwh As DWord) As MMRESULT Declare Function waveOutReset Lib "winmm" (hwo As HWAVEOUT) As MMRESULT Declare Function waveOutUnprepareHeader Lib "winmm" (hwo As HWAVEOUT,pwh As LPWAVEHDR,cbwh As DWord) As MMRESULT Declare Function waveOutClose Lib "winmm" (hwo As HWAVEOUT) As MMRESULT '定義ここまで #console Const SRATE = 44100 '標本化周波数(1秒間のサンプル数) Const MINUTES = 2 '秒数 Dim wfe As WAVEFORMATEX wfe.wFormatTag=WAVE_FORMAT_PCM wfe.nChannels=1'1=モノラル,2=ステレオ wfe.wBitsPerSample=8'量子化ビット数 8ならデータは0...255 中心は128,16ならデータは-32768...32767中心は0 wfe.nBlockAlign=wfe.nChannels * wfe.wBitsPerSample/8 wfe.nSamplesPerSec=SRATE'標本化周波数 wfe.nAvgBytesPerSec=wfe.nSamplesPerSec * wfe.nBlockAlign Dim hWaveOut As HWAVEOUT waveOutOpen(VarPtr(hWaveOut),WAVE_MAPPER,VarPtr(wfe),0,0,CALLBACK_NULL) Dim whdr As WAVEHDR,lpWave As *Byte Dim len As Long,i As Long,elm As Long,k As Double '波形の生成 elm=wfe.nSamplesPerSec*MINUTES len=wfe.nAvgBytesPerSec*MINUTES lpWave=calloc(elm*wfe.wBitsPerSample/8) k=1/wfe.nAvgBytesPerSec*2*_System_PI For i=0 To elm-1 lpWave=Sin(i*k*440)*64+128 Next '再生 whdr.lpData=lpWave whdr.dwBufferLength=len whdr.dwFlags=WHDR_BEGINLOOP Or WHDR_ENDLOOP whdr.dwLoops=1 waveOutPrepareHeader(hWaveOut,VarPtr(whdr),SizeOf(WAVEHDR)) waveOutWrite(hWaveOut,VarPtr(whdr),SizeOf(WAVEHDR)) '待機 Sleep(3000) '再生終了 waveOutReset(hWaveOut) waveOutUnprepareHeader(hWaveOut,VarPtr(whdr),SizeOf(WAVEHDR)) waveOutClose(hWaveOut) free(lpWave) ExitProcess(0) |
作成者: | Z [ 2008年8月10日(日) 13:22 ] |
記事の件名: | わざわざどうもです。 |
わざわざつくっていただいてすいません。 お手数お掛けしました。 ソースを(ざっと見て)比較してみたのですが 基本的には同じようです。 ほとんどがコピペのように一緒なのですが、 微妙に型が違っている部分が数箇所ありました。 そういえば作るときに勉強しながら大急ぎでつくったので 結構突貫工事だった気がします。 前回のミスといい、型が間違っていたようですね。(←もはや馬・・・) それともう一点重要そうなのが、 いままでABのver3を使ったのですが、 konisiさんのソースをABver3で使うとエラーが沢山出ます。(これは当たり前として) で、AB4用のものであると気づき実行してみると何の問題もなく出来ました。 連続演奏に対応するように書き換えたものも正常に動きました。 どうも旧バージョンに対する執着(?)が強かったのが原因のようです。 AB3でも型に気をつければ出来ると思ったのですが・・・。 ソースを手がかりに修正してみます。 わざわざありがとうございました。 |
ページ 1 / 1 | 全ての表示時間は UTC+09:00 です |
Powered by phpBB® Forum Software © phpBB Limited https://www.phpbb.com/ |