记一次排查线上程序内存的忽高忽低,又是大集合惹祸了

一:背景

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 00007ffe094baf50Address               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 找到它的引用根,通过引用链就可以找到它的代码区块,简直不要太实用,????????????。


0:000> !gcroot 000001c4de8f1020 
Thread 2da8:00000017f4c7e5d0 00007ffdab758ca1 xxxx.xxxx.xxxx.GetFlowAwayCustomer(Int32, System.String, System.Collections.Generic.Dictionary`2<System.String,System.Collections.Generic.List`1<xxxx>>)rbp-238: 00000017f4c7e628->  000001c3d5c1bdf0 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[System.DateTime, mscorlib]], mscorlib]]->  000001c3d8de7d10 System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[System.DateTime, mscorlib]], mscorlib]][]->  000001c3d8d58630 System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[System.DateTime, mscorlib]]->  000001c4de8f1020 System.Collections.Generic.Dictionary`2+Entry[[System.Int32, mscorlib],[System.DateTime, mscorlib]][]

从上面引用链可以看到三点信息:

<1 > 当前字典在 2da8 线程上

<2> 字典在 GetFlowAwayCustomer 方法中,大概可以看出是计算流失客户的。

<3 > 调用链顶部是最大的集合 Dictionary<string,ditionary> ,address:000001c3d5c1bdf0</string,ditionary

4. 寻找更多信息

<1> 挖字典内容

有了最大的字典,我们来看看最大字典Dictionary<string,Ditionary<int,DateTime>> 占用的内存大小。


0:000> !objsize 000001c3d5c1bdf0
sizeof(000001c3d5c1bdf0) = 340008256 (0x14441d40) bytes (System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[System.DateTime, mscorlib]], mscorlib]])

根据sizeof(000001c3d5c1bdf0) = 340008256 (0x14441d40) bytes 计算一下:324M,尼玛,这都是其中一个字典,难怪内存忽高忽低,现在大家肯定特别想知道里面有啥东西,可以用 da -> !do 去内部集合看一下。


0:000> !da -length 1 -start 1 -details 000001c3d8de7d10
Name:        System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[System.DateTime, mscorlib]], mscorlib]][]
MethodTable: 00007ffdab940650
EEClass:     00007ffdab9405b8
Size:        192(0xc0) bytes
Array:       Rank 1, Number of elements 7, Type VALUETYPE
Element Methodtable: 00007ffdab940520
[1] 000001c3d8de7d38Name:        System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[System.DateTime, mscorlib]], mscorlib]]MethodTable: 00007ffdab940520EEClass:     00007ffe08e92920Size:        40(0x28) bytesFile:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dllFields:MT    Field   Offset                 Type VT     Attr            Value Name00007ffe094e9288  4003474       10             System.Int32      1     instance             58671583     hashCode00007ffe094e9288  4003475       14             System.Int32      1     instance                   -1     next00007ffe094ebf10  4003476        0           System.__Canon      0     instance     000001c2cec43610     key00007ffe094ebf10  4003477        8           System.__Canon      0     instance     000001c3d7b45370     value
0:000> !do 000001c3d7b45370     
Name:        System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[System.DateTime, mscorlib]]
MethodTable: 00007ffe094b9ec8
EEClass:     00007ffe08e9d528
Size:        80(0x50) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:MT    Field   Offset                 Type VT     Attr            Value Name
00007ffe094e9220  4001858        8       System.Int32[]  0 instance 000001c46e8f1020 buckets
00007ffe094baf50  4001859       10 ...ime, mscorlib]][]  0 instance 000001c46f3fa760 entries
00007ffe094e9288  400185a       38         System.Int32  1 instance          2512598 count
00007ffe094e9288  400185b       3c         System.Int32  1 instance          3194430 version
00007ffe094e9288  400185c       40         System.Int32  1 instance               -1 freeList
00007ffe094e9288  400185d       44         System.Int32  1 instance                0 freeCount
00007ffe094dabb8  400185e       18 ...Int32, mscorlib]]  0 instance 000001bc06272ab8 comparer
00007ffe0a0463e0  400185f       20 ...eTime, mscorlib]]  0 instance 0000000000000000 keys
00007ffe0a046258  4001860       28 ...eTime, mscorlib]]  0 instance 0000000000000000 values
00007ffe094e6f28  4001861       30        System.Object  0 instance 0000000000000000 _syncRoot

可以看到大字典中7个元素,然后我挑了一个内嵌Dictionary,可以看到这个内嵌字典的count=251w,里面的details我就不输出了。

<2> 挖线程栈

有了字典内容,大家继续看一下此时这个线程 [2da8] 在做什么?


0:028> ~~[2da8]s
ntdll!NtWaitForSingleObject+0x14:
00007ffe`28646124 c3              ret
0:028> !clrstack 
OS Thread Id: 0x2da8 (28)Child SP               IP Call Site
00000017f4c7e4f0 00007ffe09e48e52 System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[System.DateTime, mscorlib]].Resize(Int32, Boolean)
00000017f4c7e560 00007ffe09316c65 System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[System.DateTime, mscorlib]].Insert(Int32, System.DateTime, Boolean)

我靠,这个集合正在做扩容。。。大家应该知道,有扩容就有虚占内存。

三:总结

到这里肯定有人问,找出大集合了,解决方案是什么?因为是昨天才发现的,何况代码不是我写的,你问我哈???准备从两方面入口, 业务逻辑上优化 ➕ 定制化集合(HashSet,Dictionary),毕竟这两个集合虚占内存太可怕了,下一篇我们来分析一下他们的扩容机制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309772.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[C++11]forward完美转发

// 函数原型 template <class T> T&& forward (typename remove_reference<T>::type& t) noexcept; template <class T> T&& forward (typename remove_reference<T>::type&& t) noexcept;// 精简之后的样子 std::forward…

Pipe HDU - 2150(判断线段相交+向量叉乘线代详解)

题目&#xff1a; 经过激烈的争夺&#xff0c;Lele终于把那块地从Yueyue的手里抢了回来。接下来&#xff0c;Lele要开始建造他的灌溉系统。 通过咨询Lele的好友——化学系的TT&#xff0c;Lele决定在田里挖出N条沟渠&#xff0c;每条沟渠输送一种肥料。 每条沟渠可以看作是一…

win7如何将计算机移至桌面,如何将win7电脑桌面的文件转移到其他盘中?

想必很多朋友都和小编一样&#xff0c;是一个嫌麻烦的人&#xff0c;是一个不怎么爱收拾的人吧?这种人有一个通病&#xff0c;那就是喜欢将一些重要的文件放置在win7 64位纯净版下载的桌面上&#xff0c;这样的话&#xff0c;不仅容易找到&#xff0c;而且方便使用&#xff0c…

凸包算法知识总结

首先&#xff0c;什么是凸包&#xff1f; 假设平面上有p0~p12共13个点&#xff0c;过某些点作一个多边形&#xff0c;使这个多边形能把所有点都“包”起来。当这个多边形是凸多边形的时候&#xff0c;我们就叫它“凸包”。 处理何种问题&#xff1a;凸包可以看成在木板上钉许多…

[C++11]shared_ptr使用的注意事项(内存被重复析构,内存泄漏问题)

shared_ptr使用的注意事项: 1.不能使用一个原始地址初始化多个共享智能指针 2.函数不能返回管理了this的共享智能指针对象 3.共享智能指针不能循环引用 不能使用一个原始地址初始化多个共享智能指针 代码如下: #include <iostream> #include <memory> using name…

一文解读使用WinDbg排查iis 中CPU占用高的站点问题

一、概述在Window服务器部署程序后&#xff0c;可能因为代码的不合理或者其他各种各样的问题&#xff0c;会导致CPU暴增&#xff0c;甚至达到100%等情况&#xff0c;严重危及到服务器的稳定以及系统稳定&#xff0c;但是一般来说对于已发布的程序&#xff0c;没法即时看到出问题…

Power Network POJ - 1459(EK算法模板+详解)

题意&#xff1a; 总共有a个节点&#xff0c;其中有发电站b个、用户c个和调度器a-b-c个三种节点&#xff0c;每个发电站有一个最大发电量&#xff0c;每个用户有个最大接受电量&#xff0c;现在有d条有向边&#xff0c;边有一个最大的流量代表&#xff0c;最多可以流出这么多电…

[C++11]shared_ptr共享智能指针的初始化与使用

使用智能指针需要添加头文件: 代码如下: #include <memory>shared_ptr使用的注意事项: 1.不能使用一个原始地址初始化多个共享智能指针 2.函数不能返回管理了this的共享智能指针对象 3.共享智能指针不能循环引用 初始化: 1.通过构造函数初始化 代码如下: std::shar…

人在职场,表达似水

最近几天集中在和部门内的小伙伴做1&#xff1a;1Talk。发现有不少人表达能力真的不是很好&#xff0c;而且水平长期停滞不前。现场与他们分享了一些我的经验&#xff0c;趁热打铁也想在这里分享给大家。表达能力不好本身就是做技术的人身上的一个常见标签。如果仅仅是标签也就…

[C++11]弱引用智能指针weak_ptr初始化和相关的操作函数

弱引用智能指针 std::weak_ptr 可以看做是 shared_ptr 的助手&#xff0c;它不管理 shared_ptr 内部的指针。std::weak_ptr 没有重载操作符 * 和 ->&#xff0c;因为它不共享指针&#xff0c;不能操作资源&#xff0c;所以它的构造不会增加引用计数&#xff0c;析构也不会减…

电子科技大学计算机网络技术专业,计算机专业前景如何?最强十大高校有哪些?电子科大排名多少?...

近几年计算机专业以及与计算机相关的专业可谓是火的不能再火&#xff0c;越来越多的考生在高考时选择了计算机专业或者与计算机相关的专业&#xff01;事实也是如此&#xff0c;随着科技的进步&#xff0c;信息技术的迅猛发展&#xff0c;特别是计算机技术的发展&#xff0c;以…

写一个简版 asp.net core

动手写一个简版 asp.net coreIntro之前看到过蒋金楠老师的一篇 200 行代码带你了解 asp.net core 框架&#xff0c;最近参考蒋老师和 Edison 的文章和代码&#xff0c;结合自己对 asp.net core 的理解 &#xff0c;最近自己写了一个 MiniAspNetCore &#xff0c;写篇文章总结一…

[C++11]独占的智能指针unique_ptr的删除器

unique_ptr 指定删除器和 shared_ptr 指定删除器是有区别的&#xff0c;unique_ptr 指定删除器的时候需要确定删除器的类型&#xff0c;所以不能像 shared_ptr 那样直接指定删除器&#xff0c;举例说明&#xff1a; 代码如下: #include <iostream> #include <memory…

如何在Windows上使用Git创建一个可执行脚本?

长话短说&#xff0c;今天介绍如何在windows上使用Git上创建一个可执行的shell脚本。“首先我们要知道windows上Git默认添加的文件权限是:-rw-r--r--(对应权限值是644)&#xff0c;而通常创建的shell脚本都希望天然可执行&#xff0c;故有必要在Windows上使用Git管理shell脚本时…

[C++11]共享智能指针shared_ptr指定删除器

当智能指针管理的内存对应的引用计数变为 0 的时候&#xff0c;这块内存就会被智能指针析构掉了。另外&#xff0c;我们在初始化智能指针的时候也可以自己指定删除动作&#xff0c;这个删除操作对应的函数被称之为删除器&#xff0c;这个删除器函数本质是一个回调函数&#xff…

基于 abp vNext 和 .NET Core 开发博客项目 - 再说Swagger,分组、描述、小绿锁

在开始本篇正文之前&#xff0c;解决一个 疯疯过 指出的错误&#xff0c;再次感谢指正。步骤如下&#xff1a;删掉.Domain.Shared层中的项目引用&#xff0c;添加nuget依赖包Volo.Abp.Identity.Domain.Shared&#xff0c;可以使用命令&#xff1a;Install-Package Volo.Abp.Ide…

[C++11]独占的智能指针unique_ptr的初始化和使用

std::unique_ptr 是一个独占型的智能指针&#xff0c;它不允许其他的智能指针共享其内部的指针&#xff0c;可以通过它的构造函数初始化一个独占智能指针对象&#xff0c;但是不允许通过赋值将一个 unique_ptr 赋值给另一个 unique_ptr。std::unique_ptr 不允许复制&#xff0c…

Abp v2.8.0发布 路线图

ABP框架和ABP商业版v2.8已经发布.这篇文章将涵盖这些发布中的新增内容和项目的中期路线图.ABP框架2.8有哪些新增内容?你可在GitHub的发行说明中看到所有的变更.这篇博客只包括重要的一些功能/变更.SignalR集成包我们已经发布了一个新的包用来集成SignalR到基于ABP框架应用程序…

贵州大学计算机专业的导师是谁,贵州大学计算机科学与信息学院导师介绍:王以松...

贵州大学计算机科学与信息学院导师介绍&#xff1a;王以松王以松&#xff0c;男&#xff0c;副教授&#xff0c;硕士研究生导师。主要研究方向&#xff1a;人工智能(知识表示与推理、逻辑程序设计)&#xff0c;语义网络等。 Em作者佚名次阅读2012-01-04王以松&#xff0c;男&am…