VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > 简明python教程 >
  • 记一次排查线上程序内存的忽高忽低,又是大集合惹祸了

一:背景

1. 讲故事

昨天继续还技术债,优化一轮后的程序拉到线上后内存继续忽高忽低,低的时候20G,高的时候30G,过了一会又下降了几个G,毫无疑问,程序中有什么集合或者什么操作占用了大量内存,所以准备在28,29G的时候抓dump分析分析。

二:解决思路

从快照中找问题就像看病一样,根据病象推测,都有一套经验可循。

1. 把托管堆中>10M的对象找出来

通常应对大集合从托管堆入手最简单,看哪个类型占用空间大,基本就是它出问题了,为了避免把所有类型都打出来,这里设置一下过滤,把小于10M都踢掉, 可以用 !dumpheap -stat -min 10240,把敏感对象脱敏掉。


0:000> !dumpheap -stat -min 10240
Statistics:
              MT    Count    TotalSize Class Name
00007ffe094e6fc0        4       523776 System.Object[]
00007ffe094e6948        6      7179822 System.String
00007ffe0780da08       33     46514160 System.Collections.Generic.Dictionary`2+Entry[[System.Int32, mscorlib],[System.Collections.Generic.HashSet`1[[System.Int32, mscorlib]], System.Core]][]
00007ffe09f95f40      250    188739344 System.Collections.Generic.Dictionary`2+Entry[[System.Int32, mscorlib],[System.Int32, mscorlib]][]
00007ffe094ec988       18    540828823 System.Byte[]
00007ffe07802da8     1620    622578672 System.Linq.Set`1+Slot[[System.Int32, mscorlib]][]
000001bc0452e600     1389   1038494910      Free
00007ffe094baf50       68   1128274800 System.Collections.Generic.Dictionary`2+Entry[[System.Int32, mscorlib],[System.DateTime, mscorlib]][]
00007ffe094e9220     2224   1513951832 System.Int32[]
00007ffe07819df8     2232   1668042480 System.Collections.Generic.HashSet`1+Slot[[System.Int32, mscorlib]][]
00007ffe094c8510      226   1672164568 System.Int64[]
00007ffdab8676e8     1137   1901228880 System.Collections.Generic.HashSet`1+Slot[[System.Int64, mscorlib]][]
00007ffdab89b3b0      136   1986723840 System.Linq.Set`1+Slot[[System.Int64, mscorlib]][]
Total 13321 objects

2. 找出堆中可疑的对象

因为程序启动后作为内存数据库,所以有包含指定类的大集合对象很正常,倒数第7行有一个Dictionary<int,Datetime> 占用空间挺大的,1128274800/1024/1024=1G,这个貌似不是基础数据,应该是中间变量,方法表地址为00007ffe094baf50, 通过它可以找到这68个集合的内存地址。


0:028> !dumpheap -mt 00007ffe094baf50
         Address               MT     Size   
000001c2f262a708 00007ffe094baf50 69438000     
000001c1bb8e1020 00007ffe094baf50 16147872     
000001c1bce04760 00007ffe094baf50 33486336     
000001c37e8f1020 00007ffe094baf50 143987328     
000001c44e8f1020 00007ffe094baf50 287974800    
000001c3c419b268 00007ffe094baf50 16147872   
000001c3f6b9ac28 00007ffe094baf50 16147872     
000001c467336fa0 00007ffe094baf50 33486336     
000001c46f3fa760 00007ffe094baf50 69438000   
000001c489df3668 00007ffe094baf50 16147872     
000001c494166828 00007ffe094baf50 33486336     
000001c4a68f1020 00007ffe094baf50 69438000  
000001c4d4c5c290 00007ffe094baf50 16147872     
000001c4da8f1058 00007ffe094baf50 33486336     
000001c4de8f1020 00007ffe094baf50 69438000
000001c5028f1058 00007ffe094baf50 33486336     
000001c5068f1020 00007ffe094baf50 33486336
...

下一步挑几个大的 Dictionary 看看,比如这一行: 000001c44e8f1020 00007ffe094baf50 287974800,计算一下size:279M。

3. 寻找集合所在的代码块

字典占用279M我是知道了,但怎么知道这个字典是在哪一个代码块呢? 要寻找答案也容易,通过!gcroot 找到它的引用根,通过引用链就可以找到它的代码区块,简直不要太实用,


相关教程