を考える:IISでホストされてThreadLocksと静的コンストラクタ
A ASP.netのWeb APIアプリケーション。 アプリケーションは、外部作業を行うプラグイン用に約30のアプリドメインを生成します。
のユーザーはのロットを提供していますが、ほとんどの時間は非常にうまく動作しますが、何日か(数日後または数週間後)に突然ハングします。
問題:
一つのwebアプリケーションは、w3wp.exeのを再起動する必要が生じ、時には「ハング」を持っています。
この状態でいくつかの検査を行った結果、この時点で多くのスレッド(時には約15.000)があることがわかりました。
通常のケースでは、スレッド数が100を超えることはありません。 、最後に同じコールを持っています。
ザ・DebugDiagは
は、今、私たちは、スレッド44(約90%と多くの他の多く)にすることを見てきた他の人をブロックつのスレッドがあることを述べています:それはその静的コンストラクタに関する1つの珍しいものがありbehavior.but
方法自体は、任意のロックまたはスレッドを持っていません。 ctorのは、次のようになります。
static TimeZoneHelper()
{
using (StringReader reader = new StringReader(Resources.TimeZones))
{
string line;
while ((line = reader.ReadLine()) != null)
{
string[] parts = line.Split(';');
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById(parts[1]);
timeZones[parts[0]] = timeZone;
}
}
}
はさらにデバッグ分析は、アプリケーションがアクティブGCにあったことを示している(とあなたが潜在的に求めるだろうと:私たちが今まで手動でgc.collectを誘発することはありません)
を質問 スタティックctorでこの種のコードに問題があることを示す証拠はありますか?タスクやスレッドコードがない場合でも? (オブジェクトが処分コードを持っていない場合でも、使い捨てであると?)GCの進行自体に関連おそらく何か
TimeZoneHelper
私はctorのをinlcudingこのクラスの主なメソッドを含む要旨を作成し、 TimeZoneHelper.ToTimeZoneOffset
と呼ばれていた方法:
https://gist.github.com/Gentlehag/9d564555261da0e73366
主なものでメソッドの結果は、(ctorの中で作成された)Dictionary.TryGetある
編集 Btwまた、アセンブリ解決イベントがバインドされている各appdomainに追加したいと思います。 コードはここで見ることができます:
https://gist.github.com/Gentlehag/4726b6d888adb149684d
重要な更新 私は同僚だし、ちょうどいくつかのより多くの情報を追加したいです。また、非常に似ている別のシナリオも見つかりました。それはTimeZoneHelperクラスに関するものではありませんが、一般的な側面があることは興味深いです
000000c898897560 00007ff8855b7e5d System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].FindEntry(System.__Canon)
000000c8988975d0 00007ff8855b7d34 System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].TryGetValue(System.__Canon, System.__Canon ByRef)
000000c898897610 00007ff88f6152b3 GP.Components.Extensions.AppDomains.RemotingRunner.CurrentDomain_AssemblyResolve(System.Object, System.ResolveEventArgs)
000000c8988978a0 00007ff886f7276c System.AppDomain.OnAssemblyResolveEvent(System.Reflection.RuntimeAssembly, System.String)
000000c898897bd0 00007ff8e4b2a7f3 [GCFrame: 000000c898897bd0]
000000c898899b78 00007ff8e4b2a7f3 [HelperMethodFrame_PROTECTOBJ: 000000c898899b78] System.Reflection.RuntimeAssembly._nLoad(System.Reflection.AssemblyName, System.String, System.Security.Policy.Evidence, System.Reflection.RuntimeAssembly, System.Threading.StackCrawlMark ByRef, IntPtr, Boolean, Boolean, Boolean)
000000c898899c80 00007ff886f7224e System.Reflection.RuntimeAssembly.InternalGetSatelliteAssembly(System.String, System.Globalization.CultureInfo, System.Version, Boolean, System.Threading.StackCrawlMark ByRef)
000000c898899d60 00007ff886f716c8 System.Resources.ManifestBasedResourceGroveler.GetSatelliteAssembly(System.Globalization.CultureInfo, System.Threading.StackCrawlMark ByRef)
000000c898899df0 00007ff885b932fb System.Resources.ManifestBasedResourceGroveler.GrovelForResourceSet(System.Globalization.CultureInfo, System.Collections.Generic.Dictionary`2, Boolean, Boolean, System.Threading.StackCrawlMark ByRef)
000000c898899eb0 00007ff885b92ecb System.Resources.ResourceManager.InternalGetResourceSet(System.Globalization.CultureInfo, Boolean, Boolean, System.Threading.StackCrawlMark ByRef)
000000c898899fa0 00007ff885b92b73 System.Resources.ResourceManager.InternalGetResourceSet(System.Globalization.CultureInfo, Boolean, Boolean)
000000c898899ff0 00007ff885b92014 System.Resources.ResourceManager.GetString(System.String, System.Globalization.CultureInfo)
000000c89889a0a0 00007ff89914aa62 NewRelic.Agent.Core.Config.ConfigurationLoader.InitializeFromXml(System.String, System.String)
000000c89889a140 00007ff89914a838 NewRelic.Agent.Core.Config.ConfigurationLoader.Initialize(System.String)
000000c89889a1a0 00007ff899143be9 NewRelic.Agent.Core.Config.ConfigurationLoader.Initialize()
000000c89889a210 00007ff899123a27 NewRelic.Agent.Core.Agent+AgentSingleton.CreateInstance()
000000c89889a280 00007ff8991239c2 NewRelic.Agent.Core.Singleton`1[[System.__Canon, mscorlib]]..ctor(System.__Canon)
000000c89889a2c0 00007ff89912388b NewRelic.Agent.Core.Agent..cctor()
000000c89889a700 00007ff8e4b2a7f3 [GCFrame: 000000c89889a700]
000000c89889ce88 00007ff8e4b2a7f3 [PrestubMethodFrame: 000000c89889ce88] NewRelic.Agent.Core.Agent.get_Instance()
000000c89889cef0 00007ff89912358c NewRelic.Agent.Core.AgentShim.GetTracer(System.String, UInt32, System.String, System.String, System.Type, System.String, System.String, System.String, System.Object, System.Object[])
000000c89889d280 00007ff8e4b2a7f3 [DebuggerU2MCatchHandlerFrame: 000000c89889d280]
:私はブロックを所有するスレッドからのスタックトレースを持っている両方のクラスは、その静的コンストラクタでリソースをロードする(どちらかNewRelicの場合は設定ファイル、TimeZonesの場合はFile)。
- 複数のスレッドが最初のスレッドが静的コンストラクタのためにロックを取得し、このコンストラクタ
- リソースがロードされ、.NETを実行し、クラス
- を使用しよう:だからシナリオでは、次のしているようですランタイムはリソースアセンブリをロードしようとします。
- AssemblyResolveイベントを捕捉してリソースアセンブリをロードし、何らかの方法でデッドロックが発生する場合は、どのように問題がありますか?
このメソッドにはロックやスレッドがありませんが、それでも投稿してください。それは、カバーの下でロックを使用するフレームワークメソッドを呼び出すかもしれません。一般的に、スタックトレースによって特定のメソッドがブロックしていることがわかった場合、そのメソッドが実際にブロックしていると仮定するのは安全です*。 (静的コンストラクタは、独自の名前( '.cctor')を持つ別個のメソッドです)。また、スタックトレース全体が最後のフレームよりも役立ちます。 –
私は私の悪いコード –
と要旨をリンクさ - 私は、コールがメソッド本体からのものではないという事実を逃したが、関与しているCLR内部ロックを示唆し 'PrestubMethodFrame'、。さらに関連情報を追加することができます:アンマネージコールスタック( 'kb'で返される)、特にロックを所有するスレッド(上記の例では44)です。コールスタック*がロックを所有しているスレッドの1つである場合(ここでは「44」がスレッドIDであるかどうかわかりません)、実際にそのスレッドが何を待っているのか把握する必要があります'ZwWaitForSingleObject')。スタックトレースはそこに役立つはずです。 –