15

有时我们的网站速度变慢,RAM 使用率大幅上升。然后应用程序池停止,我必须重新启动它。然后几天后RAM突然再次飙升并且应用程序池很快停止。CPU不高。

在应用程序池停止之前,我注意到我们的一个页面总是挂起。它挂在的行是 ResourceSet 上的 foreach :

var englishLocations = Lang.Countries.ResourceManager.GetResourceSet(new CultureInfo("en-GB"),true,true);
foreach(DictionaryEntry entry2 in englishLocations) // THIS LINE HANGS

我们在不同的盒子上部署了相同的代码,但这种情况不会发生。两个盒子之间的主要区别是:

坏盒子

  • 窗口服务器 2008 R2 标准 SP 1
  • IIS 7.5.7600.16385
  • .NET 4.5
  • 24GB 内存

好盒子

  • 窗口服务器 2008 服务器 SP 2
  • IIS 7.0.6000.16386 SP 2
  • .NET 4.0
  • 24GB 内存

我已经尝试将 uploadReadAheadSize="0" 添加到 web.config 中,如下所述:

http://rionscode.wordpress.com/2013/03/11/resolving-controller-blocking-within-net-4-5-and-asp-net-mvc/

这没有用。

为什么 foreach 会挂起?它挂在第一个项目上,实际上是在 foreach 上。

谢谢。

4

3 回答 3

9

我知道这是一篇旧文章,但是……当迭代 ResourceSet 并同时从同一资源中检索其他对象时,可能会出现死锁。

问题是,当使用 ResourceSet 时,迭代器会在 ResourceReader http://referencesource.microsoft.com/#mscorlib/system/resources/resourcereader.cs,1389的内部资源缓存上锁定锁定,然后在 AllocateStringNameForIndex 采用的方法中锁定锁定读者本身:http ://referencesource.microsoft.com/#mscorlib/system/resources/resourcereader.cs,447

lock (_reader._resCache) {
     key = _reader.AllocateStringForNameIndex(_currentName, out _dataPosition); // locks the reader

获取对象以相反的顺序取出相同的锁:

http://referencesource.microsoft.com/#mscorlib/system/resources/runtimeresourceset.cs,300http://referencesource.microsoft.com/#mscorlib/system/resources/runtimeresourceset.cs,335

lock(Reader) {
    ....
    lock(_resCache) {
       _resCache[key] = resLocation;
    }
}

这可能导致死锁。我们最近有这个确切的问题..

于 2014-12-16T11:00:07.580 回答
2

我遇到了非常相似的问题。

每隔一段时间,IIS 就会挂起,我会看到很多请求就坐在那里。它们都处于状态ExecuteRequestHandler并具有ManagedPipelineHandler模块名称。

在使用进程资源管理器进行调查后,我可以看到他们都坐在mscorlib.dll!ResourceEnumerator.get_Entry,额外的堆栈跟踪建议一些 NGen 操作,然后ntdll.dll!WaitForMultipleObjects

我的工作假设是,当多个线程开始枚举这些资源时,我们可能会遇到死锁(可能在某些本机代码文件生成时),然后所有后续线程继续堆积。

为了解决这个问题,我刚刚围绕这个代码块创建了一个关键部分,以确保它是按顺序执行的——从那以后我就没有遇到过这个问题。

private static readonly object ResourceLock = new object();

public static MvcHtmlString SerializeGlobalResources(this HtmlHelper helper)
{
    lock (ResourceLock)
    {
        // Existing code goes here ....
    }
}
于 2014-07-03T03:08:25.073 回答
1

基于另一个答案给你一些想法如何使用 try catch 模型?也许它挂起是因为该资源不可用/锁定/..permissions 等。

var englishLocations = Lang.Countries.ResourceManager.GetResourceSet(new CultureInfo("en-GB"),true,true); 
foreach(DictionaryEntry entry2 in englishLocations) // THIS LINE HANGS



ResourceManager CultureResourceManager = new ResourceManager("My.Language.Assembly", System.Reflection.Assembly.GetExecutingAssembly());
ResourceSet resourceSet = CultureResourceManager.GetResourceSet("sv-SE", true, true);
try { resourceSet.GetString("my_language_resource");}
catch (exception ex) {  // from here log your error ex to wherever you like with some code }
于 2013-08-15T16:06:23.497 回答