2010-11-05 150 views
8

我正在用C#編寫一個基本的寫作應用程序,並且我想讓程序在打字時使打字機發出聲音。我將RichTextBox上的KeyPress事件連接到一個函數,該函數使用SoundPlayer在每次按下某個鍵時播放短wav文件,但是我注意到一段時間後,我的計算機慢慢爬行並檢查我的進程,audiodlg .exe使用了5個RAM的GIGABYTES。SoundPlayer導致內存泄漏?

我正在使用的代碼如下:

我初始化聲音播放作爲程序的全局變量開始

SoundPlayer sp = new SoundPlayer("typewriter.wav") 

然後在KeyPress事件我只需撥打

sp.Play(); 

有沒有人知道什麼導致沉重的內存使用?該文件不到一秒鐘,所以它不應該堵塞太多。

+0

如果你評論'sp.Play();'你注意到你的記憶不再增長到5 Gb?如果它仍然存在,那麼代碼還有其他問題。 – JLWarlow 2010-11-05 16:28:18

+0

更新您的音頻驅動程序。 – 2010-11-05 16:34:15

+0

是的,絕對。我分配了一把鑰匙什麼也不做,一把把鑰匙吹響。按住「無操作」鍵不會改變audiodg.exe的內存使用情況。按住「播放噪音」鍵會使其迅速飆升。如果我離開它幾分鐘,它就不會下降。 – 2010-11-05 16:36:34

回答

5

不要使用SoundPlayer - 使用waveOut... API來代替:

http://www.codeproject.com/Articles/4889/A-full-duplex-audio-player-in-C-using-the-waveIn-w

SoundPlayer比產品更像玩具離子就緒組件,儘管我確信寫下它的MS實習生意味着很好。 :)

更新:如果您使用鏈接的示例並熟悉代碼,您將會看到SoundPlayer實現可能有什麼問題。使用waveOut...函數播放音頻涉及兩個內存緩衝區:一個用於標題的小緩衝區,另一個可能是包含實際採樣數據的大型緩衝區。鏈接到的修補程序文章每次調用Play時都會提到幾百字節的泄漏,這意味着代碼可能每次都會實例化一個新標頭,然後不會正確處理它。 (這是假設SoundPlayer包裝waveOut... API - 我不知道是否是這種情況)

程序員認爲理所當然的格言「不要重新發明輪子」。那麼,有時輪子迫切需要重新發明。

+0

截至2014年9月17日,鏈接已損壞。 – 2014-09-16 23:22:10

+1

無法找到原始源代碼,所以我添加了另一個(可能更好)的鏈接。 – Sire 2015-02-17 08:28:49

0

嘗試使用聲音播放器的Load方法加載聲音,然後調用播放。 Play使用第二個線程加載(如果尚未加載)並播放該文件。

也許構造函數並沒有最初加載文件(我認爲這很有可能),它會將播放器與聲音文件名聯繫起來。

+0

我剛剛嘗試過,當聲音播放時,內存仍然處於尖峯狀態。我在窗口的初始化器上運行Load(),所以肯定會發生。 – 2010-11-05 16:43:22

2

這可能是SoundPlayer中的一個錯誤。

試試這篇文章在code project,也許它會給你一些提示。

+0

我試過這篇文章的實現,這恐怕也不起作用。 – 2010-11-05 17:25:07

0

我已經完成了this sample。 WWFM(又名「Worked For Me」)嘗試在你的代碼中搜索錯誤(我幾乎可以肯定,它足夠純淨)或者其他聲音文件

+0

仍然爲我打破。一定是我的電腦有問題。 – 2011-01-25 20:48:17

+0

嘗試更新您的聲音驅動程序,.NET和/或重新安裝Windows(作爲最極端的方式)。應該有幫助=) – shybovycha 2011-01-25 23:54:30

0

嘗試在播放聲音後放置SoundPlayer,然後運行。垃圾收集器如果仍然消耗額外的內存,一些令人頭痛的發生,你應該在另一臺計算機上運行測試

+0

它仍然不適合我,我會嘗試在我的工作電腦上測試,看看它是否也是如此。 – 2011-01-29 04:04:43

0

在使用類似的方法之前,我已經使用了Win32 API中的PlaySound函數。 雖然這不是在你使用同一種語言,下面是一個程序,將發揮「mahnamahna.wav」上的每個按鍵100的一個例子。(是的,這是很有趣的)

format PE GUI 4.0 
entry start 

;Mahna Mahna. 

include 'win32a.inc' 

include 'helper.asm' 

section '.idata' import data readable writeable 

    library kernel32,'KERNEL32.DLL',\ 
      user32,'USER32.DLL',\ 
      hook,'HOOK.DLL',\ 
      winmm,'WINMM.DLL' 

    import hook,\ 
      SetKeyPressedHandler,'SetKeyPressedHandler' 

    import winmm,\ 
      PlaySound,'PlaySound' 

    include 'api\kernel32.inc' 
    include 'api\user32.inc' 

section '.data' data readable writeable 

    szWavFile db "mahnamahna.wav",0 

    ;String saying what the dll is called. 
    szDllName db "HOOK.DLL",0 

    ;Name of the function in the dll for the keyboard procedure 
    szf_KeyboardProc db "KeyboardProc",0 

    ;handle to the dll 
    hDll dd ? 
    ;handle to the keyboard procedure 
    hKeyboardProc dd ? 
    ;handle to the hook 
    hHook dd ? 

    kInput KBINPUT 

    keyCount dd 0x0 ; 

    ;msg for the message pump 
    msg MSG 


section '.text' code readable executable 

    start: 

     ;Load the DLL into memory. 
     invoke LoadLibraryA,szDllName 
     cmp eax,0x0 
     je exit 
     mov [hDll],eax 


     invoke GetProcAddress,[hDll],szf_KeyboardProc 
     cmp eax,0x0 
     je freeLibrary 
     mov [hKeyboardProc],eax 

     invoke SetKeyPressedHandler,KeyPressedHandler 

    hook: 
     invoke SetWindowsHookEx,WH_KEYBOARD_LL,[hKeyboardProc],[hDll],0x0 
     cmp eax,0x0 
     je freeLibrary 
     mov [hHook],eax 

    msg_loop: 
     invoke GetMessage,msg,NULL,0,0 
     cmp eax,1 
     jb unhook 
     jne msg_loop 
     invoke TranslateMessage,msg 
     invoke DispatchMessage,msg 
    jmp msg_loop 



    proc KeyPressedHandler code,wparam,lparam 

     ;Move the VK Code of the key they pressed into al. 
     xor eax,eax 
     mov eax,[lparam] 
     mov cx,word [eax] 

     cmp [wparam],WM_KEYDOWN 
     je .ProcessKeyDown 
     cmp [wparam],WM_KEYUP 
     je .ProcessKeyUp 

     .ProcessKeyDown: 

      ret ;No need to go any further - we only process characters on key up 
     .ProcessKeyUp: 
      mov edx,[keyCount] 
      inc edx 

      cmp cx,VK_F12 
      je unhook 

      ;Hotkeys. 
      ;F12 - Quit. 
      cmp edx,0x64 
      jne .done 
      call MahnaMahna 
      xor edx,edx 
      .done: 
      mov [keyCount],edx 
     ret 
    endp 

    proc MahnaMahna 
     invoke PlaySound,szWavFile,0x0,0x20000 
     ret 
    endp 

    unhook: 
     invoke UnhookWindowsHookEx,[hHook] 

    freeLibrary: 
     invoke FreeLibrary,[hDll] 
    exit: 
     invoke ExitProcess,0 

以上沒有以下DLL(hook.dll)將行不通

format PE GUI 4.0 DLL 
entry _DllMain 

include 'win32a.inc' 

section '.data' data readable writeable 
    hKeyPressedHandler dd 0x0 
section '.text' code readable executable 

proc _DllMain hinstDLL,fdwReason,lpvReserved 
    mov eax,TRUE 
    ret 
endp 

    proc SetKeyPressedHandler hProc 
     mov eax,[hProc] 
     mov [hKeyPressedHandler],eax 
     ret 
    endp 

    proc KeyboardProc code,wparam,lparam 
     cmp [code],0x0 
     jl CallNextHook 

     cmp [hKeyPressedHandler],0x0;Make sure our event handler is set. 
     je CallNextHook 

     ;Call our handler. 
     invoke hKeyPressedHandler,[code],[wparam],[lparam] 

     CallNextHook: 
      invoke CallNextHookEx,0x0,[code],[wparam],[lparam] 
      ret 
    endp 

section '.idata' import data readable writeable 

    library kernel32,'KERNEL32.DLL',\ 
      user32,'USER32.DLL' 

    include 'api\kernel32.inc' 
    include 'api\user32.inc' 

section '.edata' export data readable 
    export 'hook.DLL',\ 
     KeyboardProc,'KeyboardProc',\ 
     SetKeyPressedHandler,'SetKeyPressedHandler' 

section '.reloc' fixups data discardable 
0

這不是嚴格意義上的答案,所以我不會確認這是公認的回答我的問題,但它是一個解決方案爲那些誰也有同樣的問題(並確認它不是我的系統有問題)

我決定使用ManagedDirectX的AudioPlayback庫實現聲音,該庫與SoundPlayer一樣易於使用,但已成功解決了我的問題。

對於那些想知道誰的代碼很簡單:

1)添加一個參考audioplayback DLL。

2)創建音頻對象(我叫我的聲音),讓你的表格,以便你可以參考它再次,使用構造函數來設置文件名上一個變量應該發揮

3)播放文件與sound.Play();

4)如果需要再次播放文件,請使用以下行:

sound.SeekCurrentPosition(0, SeekPositionFlags.AbsolutePositioning); 

這是相當快,相當不錯。如果你需要很多不同的聲音效果,會有內存問題,因爲它們都會一直在內存中,但是如果你需要一個聲音來播放很多,那麼這個聲卡就不會使你的Audiodlg.exe氣球變形。

0

你應該嘗試使用()

using(SoundPlayer sp = new SoundPlayer("typewriter.wav")) { 
    sp.Play(); 
} 

當過程結束sp.Play()的內存返回到系統自動化。

+1

我的系統如何使用更多內存?我想在開始時創建它,並儘可能多地使用它,然後將其刪除,而不是在每次運行時創建並銷燬它(這是很多) – 2011-11-15 10:53:25

+0

對不起,我忘記了您嘗試使用聲音進行打字。 – Hutchibang 2011-11-18 07:56:47