我正在使用Visual C#Express在xna中创建一个Windows游戏。在游戏中,有六个SoundEffect对象经常调用它们的Play()方法。问题是,有时当游戏关闭时,它会崩溃。 当正在播放soundeffect时窗口关闭时,似乎会发生这种情况。 这是在Visual C#中弹出的消息:
未处理AccessViolationException
尝试读取或写入受保护的内存。这通常表明其他内存已损坏。
Visual Studio中没有任何可用的源代码可供调试,当点击“获取此异常的常规帮助”时,会弹出一个空白页面。
使用的代码看起来很像MSDN示例。这看起来像是存在于底层框架某处的问题,而不是我的代码。但我当然不确定。这已经发生了很多次。
http://msdn.microsoft.com/en-us/library/bb195053.aspx
以下是完整的例外情况:
System.AccessViolationException was unhandled
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Source=Microsoft.Xna.Framework
StackTrace:
at Microsoft.Xna.Framework.Audio.AudioCallbackDispatcher.IsEventRegistered(EventType type)
at Microsoft.Xna.Framework.Audio.AudioCallbackDispatcher.UnregisterEvent(EventType type)
at Microsoft.Xna.Framework.Audio.KernelMicrophone.ShutdownCaptureEngine()
at Microsoft.Xna.Framework.Audio.MicrophoneUnsafeNativeMethods.ShutdownCaptureEngine()
at Microsoft.Xna.Framework.Audio.AudioRendererShutdownHandler.AppExitingEventHandler(Object sender, EventArgs args)
InnerException:
(我也通过MediaPlayer播放音乐,但我认为它不相关。)
编辑:我似乎找到了一些有用的东西,但它有点像hackish,真的不应该是必要的。我仍然愿意接受任何更优雅的解决方案。在Game1.UnloadContent()中调用此行。它将确保(如果你的声音效果都短于3秒),当程序实际关闭时没有声音播放。
System.Threading.Thread.Sleep(3000);
答案 0 :(得分:2)
使SoundEffect对象成为类成员并在类解构上调用SoundEffect的Dispose()方法:
class MyClass
{
~MyClass()
{
effect.Dispose();
}
SoundEffect effect;
}
当你关闭游戏时,这应该让SoundEffect对象自行清理。您可以在此处阅读有关Disposable的对象:http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
答案 1 :(得分:1)
你能让MyClass实现IDisposable并在该方法中处理SoundEffect吗?
答案 2 :(得分:1)
我认为这是一个框架中的错误是非常安全的。因为它在音频代码中,所以框架可能没有正确处理它从驱动程序获得的内容。很难说肯定。
可以说框架中出现的AccessViolationException
并非“正常”。几乎可以肯定不是你的错。
发生异常的函数IsEventRegistered
是unsafe
函数。因此,函数可能正在执行异常所说的内容:它正在访问无效的内存地址。
异常来自音频捕获(麦克风)的关闭代码,所以你在代码中使用麦克风做了什么吗?您可以尝试使用/不使用麦克风,看看会发生什么。
另外:如果在没有附加调试器的情况下运行会发生这种情况吗? (Ctrl + F5键)
至于解决问题:您的解决方案并非糟糕。
如果你不能等待三秒钟,并且你想弄清楚并且写一些非常有问题的(半不可移植,不必要向前兼容)代码:你可以使用反射来访问音频系统的私有属性。找到每次调用SoundEffectInstance
时在内部创建的SoundEffect.Play
个对象的列表,然后在关闭之前停止这些实例。
或者你可以通过永远不会调用Play
来做同样的事情,而是调用CreateInstance
并自己管理即发即弃音效。缺点是这需要编写大量代码!
答案 3 :(得分:0)
我有同样的问题,我在类终结器(析构函数)中为我的声音集合做了空值。适合我。
public class Audio
{
private ContentManager content;
public List<SoundEffectInstance> SoundInstance { get; private set; }
public AudioEmitter Emitter { get; set; }
public AudioListener Listener { get; set; }
public List<SoundEffect> Sound { get; set; }
public Audio(ContentManager content)
{
this.content = content;
Emitter = new AudioEmitter();
Listener = new AudioListener();
Sound = new List<SoundEffect>();
SoundInstance = new List<SoundEffectInstance>();
}
//set to null your sound instances and effects :D
~Audio()
{
Sound = null;
SoundInstance = null;
}
...