2010-11-05 2 views
8

Я пишу основное приложение для написания на C#, и я хотел, чтобы программа производила звуки пишущей машинки, когда вы ввели. Я подключил событие KeyPress на моем RichTextBox к функции, которая использует SoundPlayer для воспроизведения короткого wav-файла при каждом нажатии клавиши, однако я заметил, что через некоторое время мой компьютер замедляет сканирование и проверяет мои процессы, audiodlg .exe использует 5 GIGABYTES ОЗУ.SoundPlayer вызывает утечку памяти?

код я использую выглядит следующим образом:

Я инициализацию SoundPlayer как глобальная переменная в программе запуска с

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

Тогда на событие KeyPress я просто называю

sp.Play(); 

Кто-нибудь знает, что вызывает интенсивное использование памяти? Файл меньше секунды, поэтому он не должен слишком сильно забивать вещь.

+0

Если вы прокомментируете 'sp.Play();' вы заметили, что ваша память больше не растет до 5 Гб? Если это все равно, что-то не так с вашим кодом. – JLWarlow

+0

Обновите звуковые драйверы. –

+0

Да, определенно. Я назначил один ключ, чтобы ничего не делать, и один, чтобы воспроизвести шум. Удержание клавиши «ничего не делать» не влияет на использование памяти audiodg.exe. Удержание клавиши «шум воспроизведения» заставляет ее быстро всплывать. Тогда он не падает, если я оставлю его на несколько минут. –

ответ

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 обертывает API waveOut... - я не знаю, так ли это или нет)

Программисты принимают само собой разумеющееся «не изобретать велосипед» Ну, иногда колесо отчаянно нуждается в переосмыслении.

+0

По состоянию на 2014/09/17 эта ссылка не работает. –

+1

Не удалось найти исходный код, поэтому я добавил еще одну (возможно, лучшую) ссылку. – Sire

0

Попробуйте использовать способ звукового проигрывателя Load, чтобы загрузить звук, а затем вызвать воспроизведение. Play использует второй поток для загрузки (если он еще не загружен) и воспроизведения файла.

Возможно, конструктор не загружает файл изначально (что, я думаю, вполне возможно), он мужественно ассоциирует плеер со звуковым именем.

+0

Я только что пробовал это, и память все еще звучит, когда звучит звук. Я запускаю Load() в инициализаторе моего окна, так что это определенно происходит. –

2

Это может быть ошибка в SoundPlayer.

Пробуйте эту статью по адресу code project, возможно, это даст вам несколько советов.

+0

Я пробовал реализацию статьи, которая также не работала, я боюсь. –

0

Я сделал с this sample. WWFM (aka «Worked Well For Me»). Попробуйте найти ошибки в своем коде (который, я уверен, достаточно чист) или другой звуковой файл.

+0

Все еще ломался.Должно быть, что-то не так с моим компьютером. –

+0

Попробуйте обновить звуковые драйверы, .NET и/или переустановить окна (как самый экстремальный способ). Должен помочь =) – shybovycha

0

Попробуйте удалить SoundPlayer после воспроизведения звука. .. Garbage Collector Если он по-прежнему потребляет дополнительную память, что-то очень неприятное происходит, и вы должны запустить тесты на другой компьютер

+0

Это все еще не работает для меня, я попробую проверить на своем рабочем компьютере, посмотрю, также ли это делает. –

0

Я использовал функцию PlaySound внутри API Win32, прежде чем делать что-то подобное. Хотя это не на том же языке, который вы используете, ниже приведен пример программы, которая будет играть «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 

выше не будет работать без следующих длл (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

Это, строго говоря, ответ, так что я не подтвердит это, как принято отвечать на мой вопрос, но это решение для тех, у кого были те же проблемы (и также подтверждает, что это не моя система при неисправности)

Я решил реализовать звук, используя библиотеку AudioPlayback ManagedDirectX, которая так же проста в использовании, как и SoundPlayer, но успешно решила мою проблему.

Для тех, кто хочет знать, код прост:

1) Добавить ссылку на DLL аудиовоспроизведения.

2) Создать объект Audio (я назвал мой звук), сделайте это переменным в вашей форме, так что вы можете обратиться к нему снова, использовать конструктор, чтобы установить имя файла должен играть

3) Играть файл со звуком.Play();

4) Если необходимо воспроизвести файл, используйте следующую строку:

sound.SeekCurrentPosition(0, SeekPositionFlags.AbsolutePositioning); 

Это довольно быстро, и довольно хорошо. Будут проблемы с памятью, если вам нужно много разных звуковых эффектов, потому что они будут постоянно находиться в памяти, но если вам нужен один звук, чтобы играть много, этот будет делать это без надувания вашего Audiodlg.exe

0

Вы должны попробовать использовать()

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

когда процесс отделки sp.Play (память) возвращение к вашей системы автоматики.

+1

Как моя система использует больше памяти? Я хочу создать его с самого начала, использовать его столько, сколько хочу, а затем удалить его, а не создавать и уничтожать его каждый раз, когда он запускается (что очень много). –

+0

Извините, я забыл, что вы пытаетесь использовать звук для ввода. – Hutchibang