ASP.NET Core应用空闲时随机触发StackOverflowException求助
ASP.NET Core MVC 空闲时StackOverflowException 排查方案
问题概述
开发ASP.NET Core MVC应用时,遭遇随机StackOverflowException,异常仅在应用空闲时触发(非处理HTTP请求阶段)。调用栈显示是框架内部递归调用导致,但底层原因不明。曾尝试用DTO简化ViewModel,应用一度稳定运行8小时(此前10-15分钟就崩溃),但问题复现。
调用栈详情
初始触发栈:
> System.Private.CoreLib.dll!System.ModuleHandle.ResolveMethod(System.Runtime.CompilerServices.QCallModule module, int methodToken, System.IntPtr* typeInstArgs, int typeInstCount, System.IntPtr* methodInstArgs, int methodInstCount) System.Private.CoreLib.dll!System.ModuleHandle.ResolveMethodHandleInternal(System.Reflection.RuntimeModule module, int methodToken, System.IntPtr[] typeInstantiationContext, int typeInstCount, System.IntPtr[] methodInstantiationContext, int methodInstCount) Línea 1405 System.Private.CoreLib.dll!System.ModuleHandle.ResolveMethodHandle(int methodToken, System.RuntimeTypeHandle[] typeInstantiationContext, System.RuntimeTypeHandle[] methodInstantiationContext) Línea 1390 System.Private.CoreLib.dll!System.RuntimeType.GetMethodBase(System.Reflection.RuntimeModule scope, int typeMetadataToken) Línea 1743 System.Private.CoreLib.dll!System.Reflection.RuntimeCustomAttributeData.RuntimeCustomAttributeData(System.Reflection.RuntimeModule scope, System.Reflection.MetadataToken caCtorToken, System.Reflection.ConstArray blob) Línea 273 System.Private.CoreLib.dll!System.Reflection.RuntimeCustomAttributeData.GetCustomAttributes(System.Reflection.RuntimeModule module, int tkTarget) Línea 213 System.Private.CoreLib.dll!System.Reflection.RuntimeCustomAttributeData.GetCustomAttributesInternal(System.RuntimeType target) Línea 22 System.Private.CoreLib.dll!System.Reflection.CustomAttributeData.GetCustomAttributes(System.Reflection.MemberInfo target) Línea 18 Microsoft.Extensions.Logging.dll!Microsoft.Extensions.Logging.ProviderAliasUtilities.GetAlias(System.Type providerType) Microsoft.Extensions.Logging.dll!Microsoft.Extensions.Logging.LoggerRuleSelector.Select(Microsoft.Extensions.Logging.LoggerFilterOptions options, System.Type providerType, string category, out Microsoft.Extensions.Logging.LogLevel? minLevel, out System.Func<string, string, Microsoft.Extensions.Logging.LogLevel, bool> filter) Microsoft.Extensions.Logging.dll!Microsoft.Extensions.Logging.LoggerFactory.ApplyFilters(Microsoft.Extensions.Logging.LoggerInformation[] loggers) Microsoft.Extensions.Logging.dll!Microsoft.Extensions.Logging.LoggerFactory.RefreshFilters(Microsoft.Extensions.Logging.LoggerFilterOptions filterOptions) Microsoft.Extensions.Options.dll!Microsoft.Extensions.Options.OptionsMonitorExtensions.OnChange.AnonymousMethod__0(System.__Canon o, string _) Microsoft.Extensions.Options.dll!Microsoft.Extensions.Options.OptionsMonitor<System.__Canon>.ChangeTrackerDisposable.OnChange(System.__Canon options, string name) Microsoft.Extensions.Options.dll!Microsoft.Extensions.Options.OptionsMonitor<Microsoft.Extensions.Logging.LoggerFilterOptions>.InvokeChanged(string name) Microsoft.Extensions.Options.dll!Microsoft.Extensions.Options.OptionsMonitor<System.__Canon>..ctor.AnonymousMethod__6_2(string name) Microsoft.Extensions.Primitives.dll!Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration<string>.OnChangeTokenFired() Microsoft.Extensions.Primitives.dll!Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration<string>.RegisterChangeTokenCallback.AnonymousMethod__7_0(object s) System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.Invoke(System.Delegate d, object state, System.Threading.CancellationTokenSource source) Línea 902 System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.CallbackNode.ExecuteCallback.AnonymousMethod__9_0(object s) Línea 1139 System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Línea 183 System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.CallbackNode.ExecuteCallback() Línea 1141 System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(bool throwOnFirstException) Línea 722 System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.NotifyCancellation(bool throwOnFirstException) Línea 639 System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.Cancel() Línea 221 Microsoft.Extensions.Configuration.dll!Microsoft.Extensions.Configuration.ConfigurationManager.RaiseChanged() Microsoft.Extensions.Configuration.dll!Microsoft.Extensions.Configuration.ConfigurationManager.AddSource.AnonymousMethod__1() Microsoft.Extensions.Primitives.dll!Microsoft.Extensions.Primitives.ChangeToken.OnChange.AnonymousMethod__0_0(System.Action callback) Microsoft.Extensions.Primitives.dll!Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration<System.Action>.OnChangeTokenFired() Microsoft.Extensions.Primitives.dll!Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration<System.Action>.RegisterChangeTokenCallback.AnonymousMethod__7_0(object s) System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.Invoke(System.Delegate d, object state, System.Threading.CancellationTokenSource source) Línea 902 System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.CallbackNode.ExecuteCallback.AnonymousMethod__9_0(object s) Línea 1139 System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Línea 183 System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.CallbackNode.ExecuteCallback() Línea 1141 System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(bool throwOnFirstException) Línea 722 System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.NotifyCancellation(bool throwOnFirstException) Línea 639 System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.Cancel() Línea 221 Microsoft.Extensions.Configuration.dll!Microsoft.Extensions.Configuration.ConfigurationProvider.OnReload() Microsoft.Extensions.Configuration.FileExtensions.dll!Microsoft.Extensions.Configuration.FileConfigurationProvider.Load(bool reload) Microsoft.Extensions.Configuration.FileExtensions.dll!Microsoft.Extensions.Configuration.FileConfigurationProvider..ctor.AnonymousMethod__1_1() Microsoft.Extensions.Primitives.dll!Microsoft.Extensions.Primitives.ChangeToken.OnChange.AnonymousMethod__0_0(System.Action callback) Microsoft.Extensions.Primitives.dll!Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration<System.Action>.OnChangeTokenFired() Microsoft.Extensions.Primitives.dll!Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration<System.Action>.RegisterChangeTokenCallback.AnonymousMethod__7_0(object s) System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.Invoke(System.Delegate d, object state, System.Threading.CancellationTokenSource source) Línea 902 System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.Register(System.Delegate callback, object stateForCallback, System.Threading.SynchronizationContext syncContext, System.Threading.ExecutionContext executionContext) Línea 610 System.Private.CoreLib.dll!System.Threading.CancellationToken.Register(System.Delegate callback, object state, bool useSynchronizationContext, bool useExecutionContext) Línea 290 System.Private.CoreLib.dll!System.Threading.CancellationToken.UnsafeRegister(System.Action<object> callback, object state) Línea 248
重复触发栈溢出的循环调用链:
Microsoft.Extensions.Primitives.dll!Microsoft.Extensions.Primitives.CancellationChangeToken.RegisterChangeCallback(System.Action<object> callback, object state) Microsoft.Extensions.Primitives.dll!Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration<System.Action>.RegisterChangeTokenCallback(Microsoft.Extensions.Primitives.IChangeToken token) Microsoft.Extensions.Primitives.dll!Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration<System.__Canon>.OnChangeTokenFired() Microsoft.Extensions.Primitives.dll!Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration<System.Action>.RegisterChangeTokenCallback.AnonymousMethod__7_0(object s) System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.Invoke(System.Delegate d, object state, System.Threading.CancellationTokenSource source) Línea 902 System.Private.CoreLib.dll!System.Threading.CancellationTokenSource.Register(System.Delegate callback, object stateForCallback, System.Threading.SynchronizationContext syncContext, System.Threading.ExecutionContext executionContext) Línea 610 System.Private.CoreLib.dll!System.Threading.CancellationToken.Register(System.Delegate callback, object state, bool useSynchronizationContext, bool useExecutionContext) Línea 290 System.Private.CoreLib.dll!System.Threading.CancellationToken.UnsafeRegister(System.Action<object> callback, object state) Línea 248
排查与修复步骤
1. 终止配置文件自动重载循环
从栈信息看,异常根源是配置重载→变更通知→日志过滤器刷新→再次触发配置变更的递归循环:
- 先禁用配置文件自动重载,验证是否解决问题:
// Program.cs中修改配置加载代码 builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false) .AddEnvironmentVariables(); - 检查是否自定义了
IConfigurationProvider,其重载逻辑是否触发了额外的配置变更事件。
2. 排查日志组件问题
栈中出现ProviderAliasUtilities.GetAlias,说明异常发生在日志过滤器刷新阶段:
- 暂时替换为默认Console日志提供器,排除自定义日志组件的影响。
- 检查自定义日志提供器的
[ProviderAlias]属性是否存在反射加载异常,或日志过滤器逻辑是否有循环依赖。
3. 清理Options监听逻辑
OptionsMonitor.OnChange的回调可能间接触发配置/Options变更,形成循环:
- 移除所有非必要的
OptionsMonitor.OnChange注册,逐步排查哪个回调导致循环。 - 确保Options回调中不修改配置或触发其他Options的变更事件。
4. 升级框架版本
该问题大概率是ASP.NET Core特定版本的已知Bug,升级到对应主版本的最新补丁(如.NET 6.0.25、.NET 7.0.14、.NET 8.0.0+),框架内部的递归循环问题多数已被修复。
5. 深度调试定位
- 用Visual Studio性能探查器监控空闲时的线程栈增长,定位循环注册的回调。
- 启用崩溃转储:在
launchSettings.json中添加"environmentVariables": { "COMPlus_DbgEnableMiniDump": "1" },生成转储后用WinDbg分析递归调用链。
内容的提问来源于stack exchange,提问作者Fede
相关产品推荐
相关产品推荐

