SoundPlayer 导致内存泄漏?
Posted
技术标签:
【中文标题】SoundPlayer 导致内存泄漏?【英文标题】:SoundPlayer causing Memory Leaks? 【发布时间】:2010-11-05 16:27:04 【问题描述】:我正在用 C# 编写一个基本的写作应用程序,我想让程序在你打字时发出打字机的声音。我已经将我的 RichTextBox 上的 KeyPress 事件连接到一个函数,该函数使用 SoundPlayer 每次按下一个键时播放一个短的 wav 文件,但是我注意到一段时间后我的计算机变慢并检查我的进程,audiodlg .exe 使用了 5 GB 的 RAM。
我使用的代码如下:
我将 SoundPlayer 初始化为程序以
开头的全局变量SoundPlayer sp = new SoundPlayer("typewriter.wav")
然后在 KeyPress 事件中我只需调用
sp.Play();
有谁知道是什么导致大量内存使用?该文件的长度不到一秒,所以它不应该过多地阻塞它。
【问题讨论】:
如果您注释掉sp.Play();
,您是否注意到您的内存不再增长到 5 Gb?如果它仍然存在,那么您的代码还有其他问题。
是的,当然。我指定了一个键什么都不做,一个键播放噪音。按住“什么都不做”键不会改变 audiodg.exe 的内存使用情况。按住“播放噪音”键会使其快速飙升。如果我离开它几分钟,它就不会掉下来。
我还检查了我的驱动程序,显然它们都是最新的。不过,如果有帮助,我会尝试重新安装它们。
您是否使用过内存分析器来确定泄漏的对象?
发现问题。这是自 Vista 以来 Windows 的一个已知错误,Microsoft 为其提供了修补程序。可在此处找到修补程序:support.microsoft.com/kb/981013。出于某种原因,堆栈溢出使我无法回答我的问题,所以现在必须在这里回答
【参考方案1】:
不要使用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 - 我不知道是不是这样)
程序员认为“不要重新发明***”的格言是理所当然的。嗯,有时***迫切需要重新发明。
【讨论】:
截至 2014/09/17 链接已断开。 找不到原始源代码,所以我添加了另一个(可能更好)链接。【参考方案2】:这可能是 SoundPlayer 中的错误。
在code project 上试试这篇文章,也许它会给你一些提示。
【讨论】:
我尝试了文章的实现,恐怕也没有成功。【参考方案3】:尝试使用声音播放器的Load
方法加载声音,然后调用play。 Play 使用第二个线程加载(如果尚未加载)并播放文件。
也许构造函数最初并没有加载文件(我认为这很有可能),它将播放器与声音文件名相关联。
【讨论】:
我刚刚尝试过,当声音播放时,内存仍在飙升。我正在窗口的初始化程序上运行 Load(),所以它肯定会发生。【参考方案4】:我已经完成了this sample。 WWFM(又名“为我工作得好”)。尝试在您的代码(我几乎可以肯定,它足够纯净)或其他声音文件中搜索错误。
【讨论】:
我还是破产了。我的电脑一定有问题。 尝试更新您的声音驱动程序、.NET 和/或重新安装 Windows(作为最极端的方式)。应该帮助=)【参考方案5】:在播放声音后尝试处理 SoundPlayer。然后运行垃圾收集器。如果它仍然消耗额外的内存,那么确实发生了一些令人讨厌的事情,您应该在另一台计算机上运行测试。
【讨论】:
它仍然不适合我,我会尝试在我的工作电脑上测试,看看它是否也可以。 请注意,使用垃圾收集器也需要付费。在那里使用它作为临时修复,但不是最终解决方案。【参考方案6】:我之前在 Win32 API 中使用过 PlaySound 函数来做类似的事情。 尽管这与您使用的语言不同,但下面是一个程序示例,该程序将在每 100 次击键时播放“mahnamahna.wav”。(是的,这很有趣)
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
【讨论】:
【参考方案7】:这不是严格意义上的答案,所以我不会确认这是对我的问题的公认答案,但对于遇到相同问题的人来说,这是一个解决方案(并且也确认这不是我的系统有问题)
我决定使用 ManagedDirectX 的 AudioPlayback 库来实现声音,它与 SoundPlayer 一样易于使用,但成功地解决了我的问题。
想知道的,代码很简单:
1) 添加对音频播放 dll 的引用。
2) 创建一个音频对象(我命名为我的声音),在表单上将其设为变量,以便您可以再次引用它,使用构造函数设置它应该播放的文件名
3) 使用 sound.Play(); 播放文件
4) 如果需要再次播放文件,请使用以下行:
sound.SeekCurrentPosition(0, SeekPositionFlags.AbsolutePositioning);
它相当快,而且相当好。如果您需要很多不同的音效,则会出现内存问题,因为它们都会一直存在于内存中,但如果您需要一种声音来播放很多声音,那么这个声音就可以做到,而不会使您的 Audiodlg.exe 膨胀
【讨论】:
【参考方案8】:你应该尝试使用()
using(SoundPlayer sp = new SoundPlayer("typewriter.wav"))
sp.Play();
当进程完成时 sp.Play() 内存返回到您的系统自动操作。
【讨论】:
我的系统如何使用更多内存?我想在一开始就创建它,尽可能多地使用它,然后删除它,而不是每次运行时都创建和销毁它(这很多) 对不起,我忘了你试着用声音打字。以上是关于SoundPlayer 导致内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章