我的Web应用程序会定期崩溃并重置IIS中的应用程序池,从而导致了大型性能问题,并擦除了我的应用程序中运行的任何正时线程。
该站点是一个.NET 4.5.2 C#MVC5网站在2012 Windows Server EC2实例上运行。
当我开始看到该网站在运行时间这么多分钟后努力加载时,这个问题首先注意到了。我认为这可能是ApplicationPool回收,并确保正确地在IIS中设置了怠速和应用程序预紧。问题仍然存在。
接下来,我去了服务器管理器检查事件日志,并发现这些条目发生大约每15分钟左右:
故障应用程序名称:w3wp.exe,版本:8.5.9600.16384,时间 邮票:0x5215DF96故障模块名称:wmnetmgr.dll_unloaded, 版本:12.0.9600.17415,时间戳:0x545047DB异常代码: 0xc0000005故障偏移:0x0000000000000cf5cf故障过程ID: 0x17D0故障应用程序开始时间:0x01D331DC20F096D0故障 应用程序路径:C: Windows System32 inetsrv w3wp.exe故障模块 路径:wmnetmgr.dll报告ID:777A35DE-9DD1-11E7-81D7-025FF0BE916D 故障包装全名:错误软件包相关应用程序ID:
和
win-7pcrjofr05f 5011警告Microsoft-Windows-WAS系统9/20/2017 上午7:01:04-为应用程序池'SITENAME'的过程遭受了 Windows过程激活服务的致命通信错误。 过程ID为" 6096"。数据字段包含错误编号。
接下来我进行了Debugdiag2收集和分析:
警告 - debugdiag无法找到调试符号 wmnetmgr.dll>,因此以下信息可能不完整。 在 w3wp__sitename__pid__5088__date__09_20_2017__Time_06_31_02AM __436__ Second_Chance_Chance_exception_c000000005.dmp 违反访问违规例外(0xc0000005)在线程26上发生 另一个模块试图调用以下卸载模块: wmnetmgr.dll>。
线程26: 调用stack unloaded_wmnetmgr.dll CF5CF 0x000000DE
575cf7c0 0x000000dc
2ED5EC10
这是此调试器报告的唯一错误。报告中没有其他例外情况。我似乎无法获得此特定.dll的调试符号,并且消息似乎并没有很有帮助。
该应用程序利用WMPLIB在WMPlayer的启动时创建一个Singleton实例,以通过客户端的Web请求在Windows Server 2012实例上播放声音。该应用程序在这方面起作用,没有任何问题播放多个用户的声音和请求。
这是单身人士:
public sealed class SoundboardSingleton : IDisposable
{
private static readonly Lazy<SoundboardSingleton> lazy =
new Lazy<SoundboardSingleton>(() => new SoundboardSingleton());
public static SoundboardSingleton Instance { get { return lazy.Value; } }
public WindowsMediaPlayer WMPlayer;
private StayAliveBot _liveBot;
private Thread _botThread;
private SoundboardSingleton()
{
WMPlayer = new WindowsMediaPlayer();
WMPlayer.settings.volume = 50;
_liveBot = new StayAliveBot();
_botThread = new Thread(_liveBot.Live);
_botThread.Start();
}
public void Dispose()
{
if (_botThread.IsAlive)
{
_botThread.Abort();
}
}
}
public class StayAliveBot
{
public void Live()
{
while (SoundboardSingleton.Instance != null)
{
Thread.Sleep(1500000);
SoundboardHelper.PlaySound("C:\SoundboardOpFiles\TestTone.wav");
}
}
}
最初在startup.cs中实例化:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
// startup soundboard singleton
SoundboardSingleton.Instance.WMPlayer.settings.volume = 50;
}
}
我可以在没有问题或崩溃的情况下在本地开发机器上运行此应用程序。一切都按预期运行,没有崩溃。在部署到EC2实例时,网站上的所有内容都可以正常工作,但是现在每15分钟都有一次崩溃/重置。
我的怀疑是:
a)这是WMPLIB实例的问题,以及Windows Server 2012框中的一些依赖性,可以播放声音,但会导致常规间隔崩溃。
b)我的单例实例化犯了一个错误,这在某种程度上使我的应用程序崩溃了。
我在这里尝试了解决方案,但没有结果。
任何帮助将不胜感激。
编辑:我已经确认该问题与WMPLIB的使用有关,因为删除其用途每15分钟就停止了一次崩溃。仍然不确定为什么会发生这种情况。
这不是对您的问题的直接答案,而是对同一件事的另一种方法。而不是WMPLIB COM控件,请尝试使用WPF的线程安全媒体播放器类。将引用添加到Windowsbase和PresentationCore中,然后使用类似的内容:
using System.Windows.Media;
public void PlaySound(string filename)
{
var mplayer = new MediaPlayer();
mplayer.MediaEnded += new EventHandler(MediaEndedHandler);
mplayer.Open(new Uri(filename));
mplayer.Play();
}
public void MediaEndedHandler(object sender, EventArgs e)
{
((MediaPlayer)sender).Close();
}
您也可以将其用作单身人士与上面相同的方式,并且它是完全螺纹安全的,WMPLIB不是。
文档在这里。
编辑:
如评论中所述,您确实可以仅使用带有公共布尔属性的静态类来显示繁忙的信号。IIS中的一个静态类在所有应用程序的请求中共享,并且该类仅在回收应用程序池时才受垃圾收集,因此您需要谨慎对待存储在其中的对象的寿命,以避免存储器消费问题。该代码将使用媒体播放器类的新实例()使用媒体播放器类的新实例(),并在播放完成后立即处理它,但是繁忙的标志在对服务器的所有请求中很常见。
using System;
using System.Threading;
using System.Windows.Media;
namespace SoundBoardApp
{
public static class Soundboard
{
private static bool _isBusy = false;
public static bool IsBusy { get { return _isBusy; } }
private static void MediaEndedHandler(object sender, EventArgs e)
{
_isBusy = false;
var wmp = ((MediaPlayer)sender);
wmp.MediaEnded -= new EventHandler(MediaEndedHandler);
wmp.Close();
}
public static bool PlaySound(string filename)
{
if (!_isBusy)
{
_isBusy = true;
var wmp = new MediaPlayer();
wmp.MediaEnded += new EventHandler(MediaEndedHandler);
wmp.Volume = 0.5;
wmp.Open(new Uri(filename));
wmp.Play();
return true;
}
else
{
return false;
}
}
}
public class StayAliveBot
{
public void Live()
{
while (true)
{
Thread.Sleep(1500000);
if (!Soundboard.IsBusy) Soundboard.PlaySound("C:\SoundboardOpFiles\TestTone.wav");
}
}
}
}
我最终使用了naudio与我的单身模式。
根据Lex Li的建议,我将第三方用作Windows.MediaPlayer并非用于Web应用程序。我基于醉酒代码猴的解决方案,我在单顿上使用了布尔标志来评估通过评估播放state的单独线程经常检查的播放状态。在我的Singleton中的iWavePlayer对象上踩踏值。我唯一关心的是性能。我还没有注意到任何问题,但是我很确定,在处理程序中管理事件的性能会更大,而且代码甚至可以从Web应用程序中进行。
。这是代码:
using NAudio.Wave;
public sealed class SoundboardSingleton : IDisposable
{
private static readonly Lazy<SoundboardSingleton> lazy =
new Lazy<SoundboardSingleton>(() => new SoundboardSingleton());
public static SoundboardSingleton Instance { get { return lazy.Value; } }
public IWavePlayer WaveOutDevice { get; set; }
public AudioFileReader AudioFileReaderObj { get; set; }
public float Volume { get; set; }
private MediaCloser _mediaCloser;
private Thread _mediaCloserThread;
private StayAliveBot _liveBot;
private Thread _botThread;
public bool IsBusy { get; set; }
private SoundboardSingleton()
{
// checks our NAudio WaveOutDevice playback for stop
_mediaCloser = new MediaCloser();
_mediaCloserThread = new Thread(_mediaCloser.CheckForStoppedPlayback);
_mediaCloserThread.Start();
// thread to play sound every 25 minutes, to avoid idle flag
_liveBot = new StayAliveBot();
_botThread = new Thread(_liveBot.Live);
_botThread.Start();
}
public bool PlaySound(string filename)
{
// make sure we are not active
if (IsBusy) { return false; }
// process sound
IsBusy = true;
WaveOutDevice = new WaveOutEvent();
AudioFileReaderObj = new AudioFileReader(filename);
AudioFileReaderObj.Volume = Volume;
WaveOutDevice.Init(AudioFileReaderObj);
WaveOutDevice.Play();
return true;
}
public void CloseWaveOut()
{
// clean up sound objects
WaveOutDevice?.Stop();
if (AudioFileReaderObj != null)
{
AudioFileReaderObj.Dispose();
AudioFileReaderObj = null;
}
if (WaveOutDevice != null)
{
WaveOutDevice.Dispose();
WaveOutDevice = null;
}
}
public void Dispose()
{
if (_mediaCloserThread.IsAlive)
{
_mediaCloserThread.Abort();
}
if (_botThread.IsAlive)
{
_botThread.Abort();
}
}
}
public class MediaCloser
{
public void CheckForStoppedPlayback()
{
while (true)
{
// continuously check for our stopped playback state to cleanup
Thread.Sleep(500);
if (SoundboardSingleton.Instance.WaveOutDevice != null &&
SoundboardSingleton.Instance.WaveOutDevice.PlaybackState == PlaybackState.Stopped)
{
SoundboardSingleton.Instance.CloseWaveOut();
SoundboardSingleton.Instance.IsBusy = false;
}
}
}
}
public class StayAliveBot
{
public void Live()
{
while (true)
{
// prevent bot from going idle
Thread.Sleep(1500000);
if (!SoundboardSingleton.Instance.IsBusy)
{
SoundboardSingleton.Instance.PlaySound(ConfigurationManager.AppSettings["SoundboardHeartbeatFile"]);
}
}
}
}
希望这可以帮助任何遇到同样问题的人。我的网站已经启动并运行了几个小时,没有问题,客户向董事会垃圾邮件。再次感谢所有帮助的人。