主頁 > .NET開發 > BitArray雖好,但請不要濫用,又一次線上記憶體暴增排查

BitArray雖好,但請不要濫用,又一次線上記憶體暴增排查

2020-09-14 09:15:51 .NET開發

一:背景

1. 講故事

前天寫了一篇大記憶體排查在園子里挺火,這是做自媒體最開心的事拉,干脆再來一篇滿足大家胃口,上個月我寫了一篇博客提到過使用bitmap對原來的List<CustomerID>進行高強度壓縮,將原來的List記憶體壓縮了將近106倍,但是bitmap不是一味的好,你必須在正確的場景中使用,而不是閉著眼睛濫用,bitmap在C#中對應的集合是BitArray,

好像劇透了??????,結果就是BitArray的濫用導致記憶體小10G的漲跌,不過這種東西重點還是看解決思路,寫給以后的自己,可不能讓這難得的實踐經驗蒸發啦~~~

二:解決思路

1. 一看托管堆

看托管堆雖然是一個好主意,但也不是每次都湊效,畢竟造成記憶體暴漲暴跌的原因各種各樣,就像人感冒有風寒,風熱和病毒性,對吧??,還是使用老命令: !dumpheap -stat -min 102400 ,在托管堆上找大于100M的物件,


0:030> !dumpheap -stat -min 102400
Statistics:
              MT    Count    TotalSize Class Name
00007ffe094ec988        1      1438413 System.Byte[]
00007ffdab934c48        1      1810368 System.Collections.Generic.Dictionary`2+Entry[[System.Int32, mscorlib],[System.Collections.Generic.HashSet`1[[System.Int64, mscorlib]], System.Core]][]
00007ffe094e6948        1      2527996 System.String
00007ffdab9ace78        4     29499552 System.Collections.Generic.Dictionary`2+Entry[[System.Int64, mscorlib],[System.DateTime, mscorlib]][]
00007ffe094e4078        4    267342240 System.String[]
00007ffe094e9220      135    452683336 System.Int32[]
00007ffdab8cd620      123   1207931808 System.Collections.Generic.HashSet`1+Slot[[System.Int64, mscorlib]][]
00007ffe094c8510      185   1579292760 System.Int64[]
00007ffdab9516b0      154   1934622720 System.Linq.Set`1+Slot[[System.Int64, mscorlib]][]
000001cc882de970      347   3660623866      Free
Total 1371 objects

去掉一些敏感類后,再觀察好像沒有特別顯眼的集合,像 System.Int64[] ,System.Linq.Set1+Slot[[System.Int64, mscorlib]][] 一般都是用作其他集合的記憶體存盤,很多時候用!gcroort 抓不出來,最大的反而是Free列,有347個碎片,高達 3.5G,說明此時的大物件堆是一塌糊涂啊,要是GC能幫忙壓縮一下該多好??,

2. 查看每一個執行緒的呼叫堆疊

先慣性的偷窺一下程式中有多少個執行緒,


0:000> !threads
ThreadCount:      74
UnstartedThread:  0
BackgroundThread: 72
PendingThread:    0
DeadThread:       0
Hosted Runtime:   no
                                                                                                        Lock  
       ID OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
   0    1 2958 000001cc882e5a40    2a020 Preemptive  0000000000000000:0000000000000000 000001cc882d8db0 1     MTA 
   2    2 2358 000001cc883122c0    2b220 Preemptive  000001D41B132930:000001D41B1348A0 000001cc882d8db0 0     MTA (Finalizer) 
   3    4 2204 000001cc883ae5d0  102a220 Preemptive  0000000000000000:0000000000000000 000001cc882d8db0 0     MTA (Threadpool Worker) 
   5    7 278c 000001cca29d8ef0  202b220 Preemptive  000001D41AB53A98:000001D41AB55A58 000001cc882d8db0 1     MTA 
   6   40 2a64 000001cca3048f10  1020220 Preemptive  0000000000000000:0000000000000000 000001cc882d8db0 0     Ukn (Threadpool Worker) 
   7   46  e34 000001cca311c390  202b220 Preemptive  0000000000000000:0000000000000000 000001cc882d8db0 0     MTA 
   8   47 27d8 000001cca3115e00    2b220 Preemptive  0000000000000000:0000000000000000 000001cc882d8db0 0     MTA 

...

可以看到當前有74個執行緒,后臺執行緒有72個,接下來用 ~*e !clrstack 查看每個托管執行緒都在做什么,由于內容太多,我就節選一下了哈,

0:000> ~*e !clrstack
OS Thread Id: 0x2d64 (29)
        Child SP               IP Call Site
000000d908cfe698 00007ffe28646bf4 [GCFrame: 000000d908cfe698] 
000000d908cfe768 00007ffe28646bf4 [HelperMethodFrame_1OBJ: 000000d908cfe768] System.Threading.Monitor.ObjWait(Boolean, Int32, System.Object)

OS Thread Id: 0x214c (30)
        Child SP               IP Call Site
000000d90957e6e8 00007ffe28646bf4 [GCFrame: 000000d90957e6e8] 
000000d90957e7b8 00007ffe28646bf4 [HelperMethodFrame_1OBJ: 000000d90957e7b8] System.Threading.Monitor.ObjWait(Boolean, Int32, System.Object)

OS Thread Id: 0x1dc0 (40)
        Child SP               IP Call Site
000000d950ebe878 00007ffe28646bf4 [GCFrame: 000000d950ebe878] 
000000d950ebe948 00007ffe28646bf4 [HelperMethodFrame_1OBJ: 000000d950ebe948] System.Threading.Monitor.ObjWait(Boolean, Int32, System.Object)

OS Thread Id: 0x274c (53)
        Child SP               IP Call Site
000000d9693fe518 00007ffe28646bf4 [GCFrame: 000000d9693fe518] 
000000d9693fe5e8 00007ffe28646bf4 [HelperMethodFrame_1OBJ: 000000d9693fe5e8] System.Threading.Monitor.ObjWait(Boolean, Int32, System.Object)
000000d9693fe700 00007ffe09314d05 System.Threading.ManualResetEventSlim.Wait(Int32, System.Threading.CancellationToken)
000000d9693fe790 00007ffe0930d996 System.Threading.Tasks.Task.SpinThenBlockingWait(Int32, System.Threading.CancellationToken)
000000d9693fe800 00007ffe09c9b7a1 System.Threading.Tasks.Task.InternalWait(Int32, System.Threading.CancellationToken)

發現一個奇怪的現象,有4個執行緒 29,30,40,53Monitor.ObjWait 處卡住了,從呼叫堆疊來看這四個家伙正在準備向Mongodb批量插入資料[InsertBatch],此時應該有其他的一個執行緒先行獲取到了lock正在做InsertBatch,這四個執行緒在等待,如何覺得抽象了,我畫一張圖:

3. 尋找insertbatch處的集合

這里我就拿 30號執行緒說事,從上圖呼叫堆疊中你應該看到一個System.Collections.Generic.IEnumerable1<System.__Canon>,從IEnumerable中可以猜測實作類應該是List或者HashSet這樣的集合,接下來用 !dso 把30號執行緒堆疊上的物件全部dump出來,

從圖中看應該就是這個 List<xxx.Common.GroupConditionCustomerIDCacheModel>,然后用!objsize ?!do 給List量個尺寸并且dump一下,


0:030> !objsize 000001d3fa581518 
sizeof(000001d3fa581518) = 1487587080 (0x58aac708) bytes (System.Collections.Generic.List`1[[DataMipCRM.Common.GroupConditionCustomerIDCacheModel, DataMipCRM.Common]])
0:030> !do 000001d3fa581518
Name:        System.Collections.Generic.List`1[[DataMipCRM.Common.GroupConditionCustomerIDCacheModel, DataMipCRM.Common]]
MethodTable: 00007ffdab9557d0
EEClass:     00007ffe08eb22a0
Size:        40(0x28) 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
00007ffe09478740  4001871        8     System.__Canon[]  0 instance 000001d3fa5b9bf8 _items
00007ffe094e9288  4001872       18         System.Int32  1 instance             1520 _size
00007ffe094e9288  4001873       1c         System.Int32  1 instance             1520 _version
00007ffe094e6f28  4001874       10        System.Object  0 instance 0000000000000000 _syncRoot
00007ffe09478740  4001875        8     System.__Canon[]  0   static  <no information>


可以看出list占用 1487587080/1024/1024=1.4G,尼瑪這么大,嚇人哈,從_size看也就1520個,說明重點都在 _items 陣列里啦,接下里用 da 把第一個item拿出來解剖下,


0:030> !da -length 1 -details 000001d3fa5b9bf8
Name:        DataMipCRM.Common.GroupConditionCustomerIDCacheModel[]
MethodTable: 00007ffdab955e10
EEClass:     00007ffe08eaaa00
Size:        16408(0x4018) bytes
Array:       Rank 1, Number of elements 2048, Type CLASS
Element Methodtable: 00007ffdab955740
[0] 000001d3fa581540
    Name:        DataMipCRM.Common.GroupConditionCustomerIDCacheModel
    MethodTable: 00007ffdab955740
    EEClass:     00007ffdab94b9e8
    Size:        64(0x40) bytes
    File:        D:\LuneceService\DataMipCRM.Common.dll
    Fields:
                      MT    Field   Offset                 Type VT     Attr            Value Name
        00007ffdaac69258  4000589       28     ...oDB.Bson.ObjectId      1     instance     000001d3fa581568     <_id>k__BackingField
        00007ffe094e9288  400058a       20             System.Int32      1     instance                 1901     <ShopId>k__BackingField
        00007ffe094e6948  400058b        8            System.String      0     instance     000001d3f7154070     <GroupConditionHasCode>k__BackingField
        00007ffe094e6948  400058c       10            System.String      0     instance     000001cca7b46ac0     <unit>k__BackingField
        00007ffe094f1cb0  400058d       18     ...lections.BitArray      0     instance     000001d3fa581580     <customeridArray>k__BackingField

從最后一行的Type列可以看到有一個 BitArray 類,還是一樣,先量個尺寸再打出來,


0:030> !objsize 000001d3fa581580     
sizeof(000001d3fa581580) = 956008 (0xe9668) bytes (System.Collections.BitArray)
0:030> !do 000001d3fa581580     
Name:        System.Collections.BitArray
MethodTable: 00007ffe094f1cb0
EEClass:     00007ffe08ead968
Size:        40(0x28) 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  40017e2        8       System.Int32[]  0 instance 000001d5320c6d18 m_array
00007ffe094e9288  40017e3       18         System.Int32  1 instance          7647524 m_length
00007ffe094e9288  40017e4       1c         System.Int32  1 instance                2 _version
00007ffe094e6f28  40017e5       10        System.Object  0 instance 0000000000000000 _syncRoot

從output中看,這個bitarray占用 956008/1024/1024 = 0.91M,真tmd的大,看bit位有 764w 個,說明有一個CustomerID=7647524-1放在這里面,問題基本上就算找到了,現在終于知道記憶體為什么這么大,算一下就出來了,

四:總結

最后去問了下搬磚的為什么這么寫,是因為給客戶展示的一張報表,為了加速,,,將每一個點上的人群保存起來放在BitArray上然后進入Monogdb快取,這樣客戶后續選擇某一個點進行 下鉆 操作的話,可以直接從mongodb中將BitArray的人群復原出來,免去程式重復計算之苦,因為每個點的人群具有排他性,落在每個點上的人可能只有幾十,幾百,幾千,而偏偏這家客戶有800w之多,自然這個CustomerID就特別大了,更不巧的就用了bitArray存少量的大數字,這些趕在一起之后,就是一個典型的濫用bitarray,您說的?


如您有更多問題與我互動,掃描下方進來吧~


圖片名稱

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/33190.html

標籤:C#

上一篇:[原創][開源] SunnyUI.Net 開發日志:UIListBox 增加跟隨滑鼠滑過高亮

下一篇:C# 資料操作系列 - 12 NHibernate的增刪改查

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more