写点什么

WinDbg 分析高内存占用问题

用户头像
圣杰
关注
发布于: 2021 年 02 月 22 日
WinDbg 分析高内存占用问题

1. 问题简介

最近产品发布大版本补丁更新,一商超客户升级后,反馈系统经常奔溃,导致超市的收银系统无法正常收银,现场排队付款的顾客更是抱怨声声。为了缓解现场的情况, 客户都是手动回收 IIS 应用程序池才能解决。


这样的后果是很严重的,接到反馈,第一时间想到的是加内存吧,这样最快。但是客户从 8G-->16G-->32G,只是延长了每次奔溃的时间,但是并没有解决系统卡顿的问题。到这里,也基本猜测了问题所在了,肯定是什么东西一直在吃内存且得不到释放。这种问题,也就只能打 Dump 分析了。


2. 打 Dump

远程客户应用服务器,32G 内存占用已经消耗了 78%,而现场已经反馈收银系统接近奔溃了,要求先强制回收内存。反正也要奔溃了,先打 Dump 再说吧。

(PS:打 Dump 会挂起进程,导致应用无法响应!而打 Dump 的耗时,也是根据当时进程的内存占用有关,内存占用越大,耗时越久。)

打开任务管理器,选择对应的 IIS 进程,右键创建转储文件(Dump)。


结果,Dump 文件是生成的,结果当分析的时候,发现 Windbg 提示 Dump 无效。说明 Dump 文件创建的有问题。观察任务管理器,发现内存占用一下就降下来了,原来是之前的进程直接奔溃了,重启了一个 W3WP 进程。


既然直接从任务管理器无法创建,就使用第三方工具收集 Dump 吧。经过 Goggle,找到一款很好用的 Dump 收集工具ProcDump,是一个命令行应用,其主要用途是监视应用程序的 CPU 或内存峰值并在峰值期间生成 Dump。


因为是高内存占用问题,我们使用以下命令来抓取 dump:

(PS:可以使用进程名称,也可以使用进程 ID 来指定要创建 Dump 的进程。当有多个相同名称的进程时,必须使用进程 ID 来指定!)

procdump w3wp -m 20480 -o D:\Dumps (当内存超过 20G 时抓取一个 w3wp 进程的 MiniDump)


上面就是我踩得第一个坑,因为默认抓取的是 MiniDump,很快就抓下来,文件也很小,正在我得意的时候,Windbg 加载 Dump 分析的时候,发现包含的信息很少,根本无法进行进一步的分析。


调整创建 Dump 的命令,添加-ma参数即可创建完整 Dump。

procdump w3wp -ma -m 20480 -o D:\Dumps (当内存超过 20G 时抓取一个 w3wp 进程的完整 Dump)


结果再一次,当内存占用到达 20G,占比 80%的时候,Dump 再次创建失败,提示:Procdump Error writing dump file。再一次感觉到绝望。不过至少有错误提示,Google 一把,果然存在天涯沦落人。Procdump Error writing dump file: 0x80070005 Error 0x80070005 (-2147024891): Access is denied。大致的意思是说,当 90S 内 Dump 文件没有成功创建的话(也就意味着 w3wp 进程被挂起了 90s),IIS 检测到 w3wp 进程挂起超过 90s 没有响应就会终止进程,重新创建一个新的进程。好嘛,真是处处是坑。


这个坑,也让我开始真正停下来思考问题。罗马不是一日建成的,内存也不是一下撑爆的。我干嘛死脑筋非要到内存占用超过 80%才去打 Dump 呢呢呢???!


焕然大悟,如醍醐灌顶。

procdump w3wp -ma -m 8000 -o D:\Dumps (当内存超过 8000M 时抓取一个 w3wp 进程的完整 Dump,并输出到 D:\Dumps 文件夹)


此时内存占用在 40%左右,这次 Dump 终于成功创建了。


3.分析 Dump

分析 Dump,上 WinDbg。如果对 WinDbg 不理解,可以看我这篇WinDbg学习笔记


接下来就是一通命令乱敲,我尽量解释清晰。

0:000> !dumpheap -stat //检查当前所有托管类型的统计信息....00007ffdb9387a98   777101     69462436 System.Char[]00007ffdb938c988   588917    115563505 System.Byte[]00007ffdb9389220  1026406    119828936 System.Int32[]00007ffdb93516a8   663559    128819040 System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[System.Object, mscorlib]][]00000218c6c30a80  6436865    197832116      Free00007ffdae9cc240    23171    273333144 System.Collections.Generic.HashSet`1+Slot[[System.String, mscorlib]][]00007ffdb9391f28 13885170    333244080 System.Boolean00007ffd5c24a068 14003455    560138200 Kingdee.BOS.JSON.JSONArray00007ffdb9386fc0 14373648   1393615400 System.Object[]00007ffdb9386948 76146065   4000287202 System.StringTotal 138435970 objects
复制代码

使用dumpheap -stat命令查看当前所有托管类型的统计信息。从输出的结果来看:

  1. 其中占用内存最多当属System.String类型,接近 4G 的大小(是不是很吃惊?!)。

  2. 其次System.Object[]类型占有 1.3G 大小。

  3. Kingdee.BOS.JSON.JSONArray类型也大概占用了 560M。


我们首先来分析占用最多的System.String类型,看看有什么发现。

0:000> !dumpheap -mt 00007ffdb9386948 -min 200 //查看200byte以上的stringAddress               MT     Size...0000021bcbaf5158 00007ffdb9386948     11400000021d375d1038 00007ffdb9386948   149698     0000021d375f5920 00007ffdb9386948   149698     0000021d3765b138 00007ffdb9386948   149706     0000021d37f739c8 00007ffdb9386948   217120     0000021d37fa8a08 00007ffdb9386948   190162     0000021d38047330 00007ffdb9386948  1224698     0000021d3829d348 00007ffdb9386948  1224698     0000021d386bd678 00007ffdb9386948  2610994     0000021d38bb8500 00007ffdb9386948  2610994     

Statistics: MT Count TotalSize Class Name00007ffdb9386948 10991 76632628 System.StringTotal 10991 objects
复制代码

从上面的输出可以发现:

  1. 单个System.String类型最大占用 2M 以上。

  2. 超过 200byte 的字节的大小的System.String总大小也不过 76M。(所以我们也不必深究大的 String 对象。)


那我们索性挑一个小点的对象来看看存储的是什么字符串,来满足一下我们的好奇心。


0.000> !do 0000021bcbaf5158 //使用!do命令查看一个对象的内容Name:        System.StringMethodTable: 00007ffdb9386948EEClass:     00007ffdb8c850e0Size:        1140(0x474) bytesFile:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dllString:      5b13710029d012False2052_T_BD_MATERIAL_MATERIAL.FAuxPropertyIdFBaseUnitIdFCategoryIDFChargeIDFCheckIncomingFDefaultVendorFErpClsIDFInvPtyIdFIsAffectPlanFIsAffectPlan1FIsBatchManageFIsComControlFIsEnableFIsEnable1FIsExpParToFlotFIsInventoryFIsPRFIsReturnMaterialFIsSourceControlFIsVmiBusinessFNameFNumberFPlanModeFPurchasePriceUnitIdFPurchaseUnitIdFPurPriceURNomFPurPriceURNumFPurURNomFPurURNumFReceiveAdvanceDaysFReceiveDelayDaysFReceiveMaxScaleFReceiveMinScaleFSalePriceUnitIdFSaleUnitIdFSpecificationFStockIdFStockPlaceIdFStoreUnitIDFTaxTypeFUseOrgId111193Fields:              MT    Field   Offset                 Type VT     Attr            Value Name00007ffdb9389288  400026f        8         System.Int32  1 instance              557 m_stringLength00007ffdb9387b00  4000270        c          System.Char  1 instance               35 m_firstChar00007ffdb9386948  4000274       90        System.String  0   shared           static Empty                                 >> Domain:Value  00000218c6c4d220:NotInit  0000021d52d81840:NotInit  <<
复制代码

似乎是基础资料字段信息。那接下来使用!gcroot命令查看其对应的 GC 根,看看到底是什么对象持有其引用,导致占用内存得不到释放。

0:000> !gcroot 0000021bcbaf5158 //使用!gcroot 查看一个对象的gc根HandleTable:    00000218c6ff15e8 (pinned handle)    -> 0000021cc75ebe68 System.Object[]    -> 0000021bc7629a10 Kingdee.BOS.Cache.KCacheManagerFactory    -> 0000021bc7629ab8 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[Kingdee.BOS.Cache.AbstractKCacheManager, Kingdee.BOS]]    -> 0000021c4da6fa48 System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[Kingdee.BOS.Cache.AbstractKCacheManager, Kingdee.BOS]][]    -> 00000218c83861b8 Kingdee.BOS.Cache.KCacheManager    -> 00000218c8386630 Kingdee.BOS.Cache.ECache.ECacheManager    -> 00000218c83866e8 System.Collections.Concurrent.ConcurrentDictionary`2[[System.String, mscorlib],[System.Collections.Generic.HashSet`1[[System.String, mscorlib]], System.Core]]    -> 0000021bcbae0c70 System.Collections.Concurrent.ConcurrentDictionary`2+Tables[[System.String, mscorlib],[System.Collections.Generic.HashSet`1[[System.String, mscorlib]], System.Core]]    -> 0000021bcbad0128 System.Collections.Concurrent.ConcurrentDictionary`2+Node[[System.String, mscorlib],[System.Collections.Generic.HashSet`1[[System.String, mscorlib]], System.Core]][]    -> 0000021bcbb34bf8 System.Collections.Concurrent.ConcurrentDictionary`2+Node[[System.String, mscorlib],[System.Collections.Generic.HashSet`1[[System.String, mscorlib]], System.Core]]    -> 0000021bcbada790 System.Collections.Concurrent.ConcurrentDictionary`2+Node[[System.String, mscorlib],[System.Collections.Generic.HashSet`1[[System.String, mscorlib]], System.Core]]    -> 0000021a49766460 System.Collections.Generic.HashSet`1[[System.String, mscorlib]]    -> 00000219540976b0 System.Collections.Generic.HashSet`1+Slot[[System.String, mscorlib]][]    -> 0000021bcbaf5158 System.String
Found 1 unique roots (run '!GCRoot -all' to see all roots).
复制代码


从以上输出可以看出:

  1. 该 String 类型被一个 Hashset 所持有。

  2. Cache关键字可以看出该 String 类型是被缓存所持有。


分析到这里,我们大致可以得出一个结论:

String 类型占用 4G 内存,绝大多数是由缓存所占用,才导致 String 类型得不到释放。


那我们是不是可以猜测内存占用持续走高是不是被缓存撑爆的呢?


带着这个疑问我们来继续分析下Kingdee.BOS.JSON.JSONArray类型。

0:000> !dumpheap -mt 00007ffd5c24a068 //输出托管堆上的所有JSONArray对象         Address               MT     Size....0000021975972b48 00007ffd5c24a068       40     00000218c933f060 00007ffd5c24a068       40     00000218c7605990 00007ffd5c24a068       40     00000218c7605af0 00007ffd5c24a068       40     00000218c7605c50 00007ffd5c24a068       40     00000218c7605e18 00007ffd5c24a068       40     00000218c7605fa0 00007ffd5c24a068       40     00000218c7606198 00007ffd5c24a068       40     00000218c7606338 00007ffd5c24a068       40     00000218c76064b0 00007ffd5c24a068       40     User interrupt.
复制代码

从输出结果来看:

  1. 满屏都是 40byte 的 JSONArray。只能使用Ctrl+Break命令中止输出。


但为了保险期间,我们来验证下有没有 100byte 以上的JSONArray

0:000> !dumpheap -mt 00007ffd5c24a068 -min 100         Address               MT     Size
Statistics: MT Count TotalSize Class NameTotal 0 objects
复制代码

这时我们可以大胆猜测所有的JSONArray对象都是 40byte。从而可以得出另一个猜测占用 560M 内存的 JSONArray,都具有相似的对象结构。接下来我们来验证这个猜测。随机选择几个对象,看看其内容具体是什么。


0:000> !DumpObj /d 0000021975972b48  //查看第一个JSONArrayName:        System.Object[]MethodTable: 00007ffdb9386fc0EEClass:     00007ffdb8d4aa00Size:        88(0x58) bytesArray:       Rank 1, Number of elements 8, Type CLASS (Print Array)Fields:None
复制代码

从输出可以看出:

  1. JSONArray 实质是System.Object[]类型。

  2. 对应的MethodTable: 00007ffdb9386fc0


如果你记性好的话,我们应当还记得占用内存第二多的就是这个System.Object[]类型,占用 1.3G。翻到上面,你可以发现其 MethodTable 和上面的统计信息是一致的。

(PS:到这里我们是不是可以猜测:**System.Object[]占用的内存无法释放,就是由于被JSONArray持有引用导致的呢?**)


既然是数组,就使用!DumpArray 命令来解开数组的面纱。


0:000> !DumpArray /d 0000021975972b48 Name:        System.Object[]MethodTable: 00007ffdb9386fc0EEClass:     00007ffdb8d4aa00Size:        88(0x58) bytesArray:       Rank 1, Number of elements 8, Type CLASSElement Methodtable: 00007ffdb9386f28[0] 0000021975972a08[1] 0000021975972a70[2] 0000021975972a40[3] 0000021ac75e87b8[4] 0000021975972b10[5] 0000021975972ba0[6] null[7] null0:000> !DumpObj /d 0000021975972a08Name:        System.StringMethodTable: 00007ffdb9386948EEClass:     00007ffdb8c850e0Size:        54(0x36) bytesFile:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dllString:      555d8ca25a6261Fields:7              MT    Field   Offset                 Type VT     Attr            Value Name00007ffdb9389288  400026f        8         System.Int32  1 instance               14 m_stringLength00007ffdb9387b00  4000270        c          System.Char  1 instance               35 m_firstChar00007ffdb9386948  4000274       90        System.String  0   shared           static Empty                                 >> Domain:Value  00000218c6c4d220:NotInit  0000021d52d81840:NotInit  <<
复制代码

从以上输出可以看出,其共有 8 个子项,我们再随机挑几个子项看看是什么内容。

0:000> !DumpObj /d 0000021975972a70Name:        System.StringMethodTable: 00007ffdb9386948EEClass:     00007ffdb8c850e0Size:        42(0x2a) bytesFile:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dllString:      FHTZDLBFields:              MT    Field   Offset                 Type VT     Attr            Value Name00007ffdb9389288  400026f        8         System.Int32  1 instance                8 m_stringLength00007ffdb9387b00  4000270        c          System.Char  1 instance               50 m_firstChar00007ffdb9386948  4000274       90        System.String  0   shared           static Empty                                 >> Domain:Value  00000218c6c4d220:NotInit  0000021d52d81840:NotInit  <<0:000> !DumpObj /d 0000021975972a40Name:        System.StringMethodTable: 00007ffdb9386948EEClass:     00007ffdb8c850e0Size:        42(0x2a) bytesFile:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dllString:      发货通知单列表Fields:              MT    Field   Offset                 Type VT     Attr            Value Name00007ffdb9389288  400026f        8         System.Int32  1 instance                8 m_stringLength00007ffdb9387b00  4000270        c          System.Char  1 instance             6279 m_firstChar00007ffdb9386948  4000274       90        System.String  0   shared           static Empty                                 >> Domain:Value  00000218c6c4d220:NotInit  0000021d52d81840:NotInit  <<
复制代码

我们可以看到一个字符串内容是FHTZDLB,另一个是发货通知单列表。看到这,我立马就条件反射的想到,这不就是我们的菜单信息嘛。为了验证我的想法,连续查看几个JSONArray,都是相似的内容。


这时,我们继续发扬敢猜敢做的精神。是不是内存被菜单缓存撑爆的?!


为了验证这一猜测,我们继续从 Dump 中寻找佐证。使用~* e!clrstack来看看所有线程的调用堆栈吧。

0:000> ~* e!clrstackOS Thread Id: 0x11dc (0)Unable to walk the managed stack. The current thread is likely not a managed thread. You can run !threads to get a list of managed threads inthe processFailed to start stack walk: 80070057OS Thread Id: 0x2b2c (28)        Child SP               IP Call Site00000076cff7ecc8 00007ffdca2e6bf4 [HelperMethodFrame_1OBJ: 00000076cff7ecc8] System.Threading.WaitHandle.WaitMultiple(System.Threading.WaitHandle[], Int32, Boolean, Boolean)00000076cff7ee00 00007ffdb91af67c System.Threading.WaitHandle.WaitAny(System.Threading.WaitHandle[], Int32, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\waithandle.cs @ 454]00000076cff7ee60 00007ffdb201b2fb System.Net.TimerThread.ThreadProc()00000076cff7ef10 00007ffdb915ca72 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 954]00000076cff7efe0 00007ffdb915c904 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 902]00000076cff7f010 00007ffdb915c8c2 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 891]00000076cff7f060 00007ffdb9196472 System.Threading.ThreadHelper.ThreadStart() [f:\dd\ndp\clr\src\BCL\system\threading\thread.cs @ 111]00000076cff7f2b8 00007ffdbb4f6793 [GCFrame: 00000076cff7f2b8] 00000076cff7f608 00007ffdbb4f6793 [DebuggerU2MCatchHandlerFrame: 00000076cff7f608] 00000076cff7f798 00007ffdbb4f6793 [ContextTransitionFrame: 00000076cff7f798] 00000076cff7f9c8 00007ffdbb4f6793 [DebuggerU2MCatchHandlerFrame: 00000076cff7f9c8] 
OS Thread Id: 0x1bd4 (133) Child SP IP Call SiteGetFrameContext failed: 10000000000000000 0000000000000000 OS Thread Id: 0x1a98 (134) Child SP IP Call Site00000076dbdbcc88 00007ffdca2e6124 [InlinedCallFrame: 00000076dbdbcc88] .SNIReadSyncOverAsync(SNI_ConnWrapper*, SNI_Packet**, Int32)00000076dbdbcc88 00007ffdaaaf5dd4 [InlinedCallFrame: 00000076dbdbcc88] .SNIReadSyncOverAsync(SNI_ConnWrapper*, SNI_Packet**, Int32)00000076dbdbcc60 00007ffdaaaf5dd4 DomainNeutralILStubClass.IL_STUB_PInvoke(SNI_ConnWrapper*, SNI_Packet**, Int32)00000076dbdbcd10 00007ffdaab08fe3 SNINativeMethodWrapper.SNIReadSyncOverAsync(System.Runtime.InteropServices.SafeHandle, IntPtr ByRef, Int32)00000076dbdbcd70 00007ffdaabe0ae0 System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()00000076dbdbcdd0 00007ffdaabe09dd System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()00000076dbdbce10 00007ffdaabdf7f5 System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()00000076dbdbce50 00007ffdaabdfa0e System.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte ByRef)00000076dbdbce90 00007ffdaabc7daa System.Data.SqlClient.TdsParser.TryRun(System.Data.SqlClient.RunBehavior, System.Data.SqlClient.SqlCommand, System.Data.SqlClient.SqlDataReader, System.Data.SqlClient.BulkCopySimpleResultSet, System.Data.SqlClient.TdsParserStateObject, Boolean ByRef)00000076dbdbcff0 00007ffdaabbb3c7 System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()00000076dbdbd050 00007ffdaabb8325 System.Data.SqlClient.SqlDataReader.get_MetaData()00000076dbdbd0a0 00007ffdaab3be73 System.Data.SqlClient.SqlCommand.FinishExecuteReader(System.Data.SqlClient.SqlDataReader, System.Data.SqlClient.RunBehavior, System.String, Boolean, Boolean)00000076dbdbd110 00007ffdaab3b75f System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(System.Data.CommandBehavior, System.Data.SqlClient.RunBehavior, Boolean, Boolean, Int32, System.Threading.Tasks.Task ByRef, Boolean, Boolean, System.Data.SqlClient.SqlDataReader, Boolean)00000076dbdbd1f0 00007ffdaab3a763 System.Data.SqlClient.SqlCommand.RunExecuteReader(System.Data.CommandBehavior, System.Data.SqlClient.RunBehavior, Boolean, System.String, System.Threading.Tasks.TaskCompletionSource`1, Int32, System.Threading.Tasks.Task ByRef, Boolean ByRef, Boolean, Boolean)00000076dbdbd2c0 00007ffdaab3a49b System.Data.SqlClient.SqlCommand.RunExecuteReader(System.Data.CommandBehavior, System.Data.SqlClient.RunBehavior, Boolean, System.String)00000076dbdbd360 00007ffdaab35cc6 System.Data.SqlClient.SqlCommand.ExecuteReader(System.Data.CommandBehavior, System.String)00000076dbdbd3f0 00007ffd5c517ead Kingdee.BOS.App.Data.AbstractDatabase.DoExecuteReader(System.Data.Common.DbCommand, System.Data.CommandBehavior)00000076dbdbd450 00007ffd5c515ebb Kingdee.BOS.App.Data.AbstractDatabase.ExecuteReader(System.Data.Common.DbCommand, System.Collections.Generic.IEnumerable`1, System.Data.CommandBehavior, Boolean)00000076dbdbd4d0 00007ffd5c4fd6f2 Kingdee.BOS.App.Data.AbstractDatabase.ExecuteReader(System.Data.Common.DbCommand, System.Collections.Generic.IEnumerable`1, System.Data.CommandBehavior)00000076dbdbd500 00007ffd5c4e31b1 Kingdee.BOS.App.Data.DBUtils.ExecuteReader(Kingdee.BOS.Context, System.String, System.Collections.Generic.IEnumerable`1, System.Data.CommandType, System.Data.CommandBehavior, Boolean)00000076dbdbd570 00007ffd5c51d2a7 Kingdee.BOS.App.Data.DBUtils.ExecuteReader(Kingdee.BOS.Context, System.String, System.Collections.Generic.IEnumerable`1, System.Data.CommandType, Boolean)00000076dbdbd5b0 00007ffd5c51d2fc Kingdee.BOS.App.Data.DBUtils.ExecuteReader(Kingdee.BOS.Context, System.String, System.Data.CommandType, Boolean)00000076dbdbd5e0 00007ffd5c51d341 Kingdee.BOS.App.Data.DBUtils.ExecuteReader(Kingdee.BOS.Context, System.String)00000076dbdbd610 00007ffd5ca5a5d4 Kingdee.BOS.App.Core.MainConsole.MainConsoleServer.GetSearchMenuData(Kingdee.BOS.Context, System.String, System.Collections.Generic.HashSet`1 ByRef, System.Collections.Generic.HashSet`1 ByRef)00000076dbdbd7d0 00007ffd5ca58164 Kingdee.BOS.App.Core.MainConsole.MainConsoleServer.GetMenuArrayForCache(Kingdee.BOS.Context)00000076dbdbda78 00007ffdbb4f6793 [DebuggerU2MCatchHandlerFrame: 00000076dbdbda78] 00000076dbdbddb8 00007ffdbb4f6793 [HelperMethodFrame_PROTECTOBJ: 00000076dbdbddb8] System.RuntimeMethodHandle.InvokeMethod(System.Object, System.Object[], System.Signature, Boolean)00000076dbdbdf30 00007ffdb914b690 System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(System.Object, System.Object[], System.Object[]) [f:\dd\ndp\clr\src\BCL\system\reflection\methodinfo.cs @ 761]00000076dbdbdfa0 00007ffdb9142922 System.Reflection.RuntimeMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo) [f:\dd\ndp\clr\src\BCL\system\reflection\methodinfo.cs @ 735]00000076dbdbe020 00007ffdb9143f22 System.Reflection.MethodBase.Invoke(System.Object, System.Object[]) [f:\dd\ndp\clr\src\BCL\system\reflection\methodbase.cs @ 211]00000076dbdbe060 00007ffd5c61990c Microsoft.Practices.Unity.InterceptionExtension.InterceptingRealProxy+c__DisplayClass1.b__0(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextInterceptionBehaviorDelegate)00000076dbdbe160 00007ffd5c619477 Microsoft.Practices.Unity.InterceptionExtension.PolicyInjectionBehavior+c__DisplayClass1.b__0(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextHandlerDelegate)00000076dbdbe200 00007ffd5c61cbc4 Kingdee.BOS.Cache.KCacheMethodCallHandler.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextHandlerDelegate)00000076dbdbe350 00007ffd5c61b10b Kingdee.BOS.Performance.Publisher.PerformanceCallHandler.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextHandlerDelegate)00000076dbdbe3e0 00007ffd5c61b10b Kingdee.BOS.Performance.Publisher.PerformanceCallHandler.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextHandlerDelegate)00000076dbdbe470 00007ffd5c61b10b Kingdee.BOS.Performance.Publisher.PerformanceCallHandler.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextHandlerDelegate)00000076dbdbe500 00007ffd5c61936d Microsoft.Practices.Unity.InterceptionExtension.HandlerPipeline.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.InvokeHandlerDelegate)00000076dbdbe590 00007ffd5c618999 Microsoft.Practices.Unity.InterceptionExtension.PolicyInjectionBehavior.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextInterceptionBehaviorDelegate)00000076dbdbe620 00007ffd5c61845d Microsoft.Practices.Unity.InterceptionExtension.InterceptionBehaviorPipeline.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.InvokeInterceptionBehaviorDelegate)00000076dbdbe6b0 00007ffd5c617002 Microsoft.Practices.Unity.InterceptionExtension.InterceptingRealProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)00000076dbdbe790 00007ffdb911190c System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32) [f:\dd\ndp\clr\src\BCL\system\runtime\remoting\realproxy.cs @ 823]00000076dbdbe980 00007ffdbb4f4a02 [TPMethodFrame: 00000076dbdbe980] Kingdee.BOS.Contracts.IMainConsoleServer.GetMenuArrayForCache(Kingdee.BOS.Context)00000076dbdbec00 00007ffdb91ad436 System.Threading.Tasks.Task.Execute() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2498]00000076dbdbec40 00007ffdb915ca72 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 954]00000076dbdbed10 00007ffdb915c904 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 902]00000076dbdbed40 00007ffdb91ad6dc System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2827]00000076dbdbedf0 00007ffdb91acdf3 System.Threading.Tasks.Task.ExecuteEntry(Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2767]00000076dbdbee30 00007ffdb9194882 System.Threading.ThreadPoolWorkQueue.Dispatch() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 820]00000076dbdbf2c8 00007ffdbb4f6793 [DebuggerU2MCatchHandlerFrame: 00000076dbdbf2c8] 00000076dbdbf458 00007ffdbb4f6793 [ContextTransitionFrame: 00000076dbdbf458] 00000076dbdbf688 00007ffdbb4f6793 [DebuggerU2MCatchHandlerFrame: 00000076dbdbf688] OS Thread Id: 0x153c (135) Child SP IP Call SiteGetFrameContext failed: 10000000000000000 0000000000000000 OS Thread Id: 0x242c (136) Child SP IP Call SiteGetFrameContext failed: 10000000000000000 0000000000000000 OS Thread Id: 0x153c (135) Child SP IP Call SiteGetFrameContext failed: 10000000000000000 0000000000000000 OS Thread Id: 0x242c (136) Child SP IP Call SiteGetFrameContext failed: 10000000000000000 0000000000000000 OS Thread Id: 0x2a04 (137) Child SP IP Call Site00000076dbf7af08 00007ffdca2e6124 [InlinedCallFrame: 00000076dbf7af08] .SNIReadSyncOverAsync(SNI_ConnWrapper*, SNI_Packet**, Int32)00000076dbf7af08 00007ffdaaaf5dd4 [InlinedCallFrame: 00000076dbf7af08] .SNIReadSyncOverAsync(SNI_ConnWrapper*, SNI_Packet**, Int32)00000076dbf7aee0 00007ffdaaaf5dd4 DomainNeutralILStubClass.IL_STUB_PInvoke(SNI_ConnWrapper*, SNI_Packet**, Int32)00000076dbf7af90 00007ffdaab08fe3 SNINativeMethodWrapper.SNIReadSyncOverAsync(System.Runtime.InteropServices.SafeHandle, IntPtr ByRef, Int32)00000076dbf7aff0 00007ffdaabe0ae0 System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()00000076dbf7b050 00007ffdaabe09dd System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()00000076dbf7b090 00007ffdaabdf7f5 System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()00000076dbf7b0d0 00007ffdaabdfa0e System.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte ByRef)00000076dbf7b110 00007ffdaabc7daa System.Data.SqlClient.TdsParser.TryRun(System.Data.SqlClient.RunBehavior, System.Data.SqlClient.SqlCommand, System.Data.SqlClient.SqlDataReader, System.Data.SqlClient.BulkCopySimpleResultSet, System.Data.SqlClient.TdsParserStateObject, Boolean ByRef)00000076dbf7b270 00007ffdaabbb3c7 System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()00000076dbf7b2d0 00007ffdaabb8325 System.Data.SqlClient.SqlDataReader.get_MetaData()00000076dbf7b320 00007ffdaab3be73 System.Data.SqlClient.SqlCommand.FinishExecuteReader(System.Data.SqlClient.SqlDataReader, System.Data.SqlClient.RunBehavior, System.String, Boolean, Boolean)00000076dbf7b390 00007ffdaab3b75f System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(System.Data.CommandBehavior, System.Data.SqlClient.RunBehavior, Boolean, Boolean, Int32, System.Threading.Tasks.Task ByRef, Boolean, Boolean, System.Data.SqlClient.SqlDataReader, Boolean)00000076dbf7b470 00007ffdaab3a763 System.Data.SqlClient.SqlCommand.RunExecuteReader(System.Data.CommandBehavior, System.Data.SqlClient.RunBehavior, Boolean, System.String, System.Threading.Tasks.TaskCompletionSource`1, Int32, System.Threading.Tasks.Task ByRef, Boolean ByRef, Boolean, Boolean)00000076dbf7b540 00007ffdaab3a49b System.Data.SqlClient.SqlCommand.RunExecuteReader(System.Data.CommandBehavior, System.Data.SqlClient.RunBehavior, Boolean, System.String)00000076dbf7b5e0 00007ffdaab35cc6 System.Data.SqlClient.SqlCommand.ExecuteReader(System.Data.CommandBehavior, System.String)00000076dbf7b670 00007ffd5c517ead Kingdee.BOS.App.Data.AbstractDatabase.DoExecuteReader(System.Data.Common.DbCommand, System.Data.CommandBehavior)00000076dbf7b6d0 00007ffd5c515ebb Kingdee.BOS.App.Data.AbstractDatabase.ExecuteReader(System.Data.Common.DbCommand, System.Collections.Generic.IEnumerable`1, System.Data.CommandBehavior, Boolean)00000076dbf7b750 00007ffd5c4fd6f2 Kingdee.BOS.App.Data.AbstractDatabase.ExecuteReader(System.Data.Common.DbCommand, System.Collections.Generic.IEnumerable`1, System.Data.CommandBehavior)00000076dbf7b780 00007ffd5c4e31b1 Kingdee.BOS.App.Data.DBUtils.ExecuteReader(Kingdee.BOS.Context, System.String, System.Collections.Generic.IEnumerable`1, System.Data.CommandType, System.Data.CommandBehavior, Boolean)00000076dbf7b7f0 00007ffd5c51d2a7 Kingdee.BOS.App.Data.DBUtils.ExecuteReader(Kingdee.BOS.Context, System.String, System.Collections.Generic.IEnumerable`1, System.Data.CommandType, Boolean)00000076dbf7b830 00007ffd5c61737a Kingdee.BOS.App.Data.DBUtils.ExecuteReader(Kingdee.BOS.Context, System.String, System.Collections.Generic.List`1)00000076dbf7b860 00007ffd5c8d2bd7 Kingdee.BOS.App.Core.UserParameterService.GetParamter(Kingdee.BOS.Context, Int64, System.String, System.String)00000076dbf7bb68 00007ffdbb4f6793 [DebuggerU2MCatchHandlerFrame: 00000076dbf7bb68] 00000076dbf7bea8 00007ffdbb4f6793 [HelperMethodFrame_PROTECTOBJ: 00000076dbf7bea8] System.RuntimeMethodHandle.InvokeMethod(System.Object, System.Object[], System.Signature, Boolean)00000076dbf7c020 00007ffdb914b690 System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(System.Object, System.Object[], System.Object[]) [f:\dd\ndp\clr\src\BCL\system\reflection\methodinfo.cs @ 761]00000076dbf7c090 00007ffdb9142922 System.Reflection.RuntimeMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo) [f:\dd\ndp\clr\src\BCL\system\reflection\methodinfo.cs @ 735]00000076dbf7c110 00007ffdb9143f22 System.Reflection.MethodBase.Invoke(System.Object, System.Object[]) [f:\dd\ndp\clr\src\BCL\system\reflection\methodbase.cs @ 211]00000076dbf7c150 00007ffd5c61990c Microsoft.Practices.Unity.InterceptionExtension.InterceptingRealProxy+c__DisplayClass1.b__0(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextInterceptionBehaviorDelegate)00000076dbf7c250 00007ffd5c619477 Microsoft.Practices.Unity.InterceptionExtension.PolicyInjectionBehavior+c__DisplayClass1.b__0(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextHandlerDelegate)00000076dbf7c2f0 00007ffd5c61cbc4 Kingdee.BOS.Cache.KCacheMethodCallHandler.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextHandlerDelegate)00000076dbf7c440 00007ffd5c61b10b Kingdee.BOS.Performance.Publisher.PerformanceCallHandler.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextHandlerDelegate)00000076dbf7c4d0 00007ffd5c61b10b Kingdee.BOS.Performance.Publisher.PerformanceCallHandler.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextHandlerDelegate)00000076dbf7c560 00007ffd5c61b10b Kingdee.BOS.Performance.Publisher.PerformanceCallHandler.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextHandlerDelegate)00000076dbf7c5f0 00007ffd5c61936d Microsoft.Practices.Unity.InterceptionExtension.HandlerPipeline.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.InvokeHandlerDelegate)00000076dbf7c680 00007ffd5c618999 Microsoft.Practices.Unity.InterceptionExtension.PolicyInjectionBehavior.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.GetNextInterceptionBehaviorDelegate)00000076dbf7c710 00007ffd5c61845d Microsoft.Practices.Unity.InterceptionExtension.InterceptionBehaviorPipeline.Invoke(Microsoft.Practices.Unity.InterceptionExtension.IMethodInvocation, Microsoft.Practices.Unity.InterceptionExtension.InvokeInterceptionBehaviorDelegate)00000076dbf7c7a0 00007ffd5c617002 Microsoft.Practices.Unity.InterceptionExtension.InterceptingRealProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)00000076dbf7c880 00007ffdb911190c System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32) [f:\dd\ndp\clr\src\BCL\system\runtime\remoting\realproxy.cs @ 823]00000076dbf7ca70 00007ffdbb4f4a02 [TPMethodFrame: 00000076dbf7ca70] Kingdee.BOS.Contracts.IUserParameterService.GetParamter(Kingdee.BOS.Context, Int64, System.String, System.String)00000076dbf7ccf0 00007ffd5c8d28c5 Kingdee.BOS.App.Security.K3CloudLoginService.SetRegionInfo(Kingdee.BOS.Context, Kingdee.BOS.Contracts.IUserParameterService, Kingdee.BOS.Orm.DataEntity.DynamicObject)00000076dbf7cd70 00007ffd5c22b2e2 Kingdee.BOS.App.Security.K3DataCenterService.GetDataCenterContextByID(System.String)00000076dbf7cdc0 00007ffd5c227d97 Kingdee.BOS.App.Security.K3CloudLoginService+c__DisplayClass8.b__3(System.String)00000076dbf7cdf0 00007ffd5c228471 Kingdee.BOS.Core.Authentication.AbstractAuthService.LoadContext(Kingdee.BOS.Core.Authentication.LoadContextArg)00000076dbf7ce50 00007ffd5c226ed8 Kingdee.BOS.App.Security.K3CloudLoginService.Login(Kingdee.BOS.Performance.Common.PerformanceContext, Kingdee.BOS.Authentication.LoginInfo)00000076dbf7ced0 00007ffd5c20b5a9 Kingdee.BOS.ServiceHelper.LoginServiceHelper.Login(Kingdee.BOS.Performance.Common.PerformanceContext, System.String, Kingdee.BOS.Authentication.LoginInfo)00000076dbf7cf30 00007ffd5c20960f Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateLoginInfo(System.String, Kingdee.BOS.Authentication.LoginInfo)00000076dbf7d080 00007ffd5c20783c Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser(System.String, System.String, System.String, Int32)00000076dbf7d318 00007ffdbb4f6793 [DebuggerU2MCatchHandlerFrame: 00000076dbf7d318] 00000076dbf7d658 00007ffdbb4f6793 [HelperMethodFrame_PROTECTOBJ: 00000076dbf7d658] System.RuntimeMethodHandle.InvokeMethod(System.Object, System.Object[], System.Signature, Boolean)00000076dbf7d7d0 00007ffdb914b690 System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(System.Object, System.Object[], System.Object[]) [f:\dd\ndp\clr\src\BCL\system\reflection\methodinfo.cs @ 761]00000076dbf7d840 00007ffdb9142922 System.Reflection.RuntimeMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo) [f:\dd\ndp\clr\src\BCL\system\reflection\methodinfo.cs @ 735]00000076dbf7d8c0 00007ffd5c206201 Kingdee.BOS.ServiceFacade.KDServiceFx.ServiceExecutor.Execute(Kingdee.BOS.ServiceFacade.KDServiceFx.KDServiceContext, Kingdee.BOS.ServiceFacade.KDServiceFx.ServiceType, System.String[], Kingdee.BOS.ServiceFacade.SerializerProxy, Kingdee.BOS.ServiceFacade.KDServiceFx.ServiceType)00000076dbf7d960 00007ffd5c203ea9 Kingdee.BOS.ServiceFacade.KDServiceFx.ExecuteServiceModule.OnProcess(Kingdee.BOS.ServiceFacade.KDServiceFx.KDServiceContext)00000076dbf7da00 00007ffd5c203ab8 Kingdee.BOS.ServiceFacade.KDServiceFx.ModulePipeline.ExcuteRequest(Kingdee.BOS.ServiceFacade.KDServiceFx.KDServiceContext)00000076dbf7da50 00007ffd5c20123e Kingdee.BOS.ServiceFacade.KDServiceFx.RequestExcuteRuntime.StartRequest(Kingdee.BOS.ServiceFacade.KDServiceFx.RequestExtractor, Kingdee.BOS.ServiceFacade.KDServiceFx.WebContext)00000076dbf7daa0 00007ffd5c200f00 Kingdee.BOS.ServiceFacade.KDServiceFx.KDSVCHandler.ExecuteRequest(Kingdee.BOS.ServiceFacade.KDServiceFx.WebContext, Kingdee.BOS.ServiceFacade.KDServiceFx.RequestExtractor)00000076dbf7dae0 00007ffd5c200d45 Kingdee.BOS.ServiceFacade.KDServiceFx.KDSVCHandler.ProcessRequestInternal(Kingdee.BOS.ServiceFacade.KDServiceFx.WebContext, Kingdee.BOS.ServiceFacade.KDServiceFx.RequestExtractor)00000076dbf7db30 00007ffdac1a373e *** WARNING: Unable to verify checksum for System.Web.ni.dllSystem.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()00000076dbf7dbc0 00007ffdac1633fb System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)00000076dbf7dc10 00007ffdac178220 System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)00000076dbf7dd70 00007ffdac163f79 System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)00000076dbf7ddc0 00007ffdac1766c3 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)00000076dbf7de40 00007ffdac165398 System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)00000076dbf7e000 00007ffdac164f63 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)00000076dbf7e040 00007ffdac8646ba DomainNeutralILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64, Int32)00000076dbf7e8b0 00007ffdbb4f21fe [InlinedCallFrame: 00000076dbf7e8b0] System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr, System.Web.RequestNotificationStatus ByRef)00000076dbf7e8b0 00007ffdac1d2dde [InlinedCallFrame: 00000076dbf7e8b0] System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr, System.Web.RequestNotificationStatus ByRef)00000076dbf7e880 00007ffdac1d2dde DomainNeutralILStubClass.IL_STUB_PInvoke(IntPtr, System.Web.RequestNotificationStatus ByRef)00000076dbf7e940 00007ffdac16556f System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)00000076dbf7eb00 00007ffdac164f63 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)00000076dbf7eb40 00007ffdac8646ba DomainNeutralILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64, Int32)00000076dbf7ed18 00007ffdbb4f2453 [ContextTransitionFrame: 00000076dbf7ed18]
复制代码

通过仔细比对发现这么一条Kingdee.BOS.App.Core.MainConsole.MainConsoleServer.GetMenuArrayForCache(Kingdee.BOS.Context)调用堆栈。从方法命名来看,像是用来获取菜单数组并缓存。结合前后堆栈的联系,我们可以大致得出这样一个线索:用户使用 WebApi 登录后会缓存一份独立的菜单供用户使用


有了代码堆栈,接下来知道怎么干了吧?当然是核实源代码确定问题啊。


4. 分析源码验证问题

Kingdee.BOS.App.Core.MainConsole.MainConsoleServer.GetMenuArrayForCache(Kingdee.BOS.Context)方法源代码如下:


我们发现它是用的UserToken来缓存用户菜单。看到Token,你可能就会条件反射的想到其生命周期。是的,聪明贤惠如你,Token 是有生命周期的。也就意味着 Token 过期后,下次登录还会再次缓存一份菜单。你可能会问 Token 过期后没有去清对应的菜单缓存吗?是的,并没有。


严谨的你,可能又会问 Token 多久过期?20mins。你眼珠子一转,接着问,满打满算,一个用户 1 个小时也就申请 3 次 Token,24 小时,也就申请 72 个 Token,一个菜单缓存也就顶多 1K,所以一个用户一天也就最多占用 72K。你的网站得有多少并发,才能被这么多菜单缓存撑爆啊?!


Good Question!!!


是的,客户的应用场景的并发也就顶多几百而已。那到底是什么导致如此多的菜单缓存呢?


原因是,客户的第三方客户端使用 WebApi 与我们的系统对接。而每次调用 WebApi 时都会先去调用登录接口,但却未保存会话信息。也就是说,客户第三方客户端每次的 WebApi 调用都会产生一个新的 Token。那如果有成千上万的 WebApi 请求,也就意味着成千上万的菜单缓存啊。


好了,点到为止。至此,已经基本定位到问题的根源了。


5. 最后

也许很多同学没有接触过 WinDbg,觉得其是一个复杂的工具。其实通过本文的案例讲解,其无非是通过一系列常见的命令来进行问题跟踪来定位问题。


最后来简单总结下,Windbg 分析问题的步骤:

  1. 创建完整 Dump 文件

  2. Windbg 加载 Dump 文件

  3. 根据不同问题类型,使用相关的命令进行分析

  4. 耐心分析,抽丝剥茧

  5. 边分析边猜测边验证

  6. 结合源码验证猜想

  7. 修复验证


发布于: 2021 年 02 月 22 日阅读数: 36
用户头像

圣杰

关注

一名立志成为架构师并为之努力奋斗的程序员 2018.03.14 加入

.NET Developer, Microsoft MVP

评论

发布
暂无评论
WinDbg 分析高内存占用问题