溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android程序內(nèi)存忽高忽低怎么解決

發(fā)布時間:2021-12-17 14:07:00 來源:億速云 閱讀:194 作者:iii 欄目:服務(wù)器

本篇內(nèi)容介紹了“Android程序內(nèi)存忽高忽低怎么解決”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

一:背景

1. 講故事

昨天繼續(xù)還技術(shù)債,優(yōu)化一輪后的程序拉到線上后內(nèi)存繼續(xù)忽高忽低,低的時候20G,高的時候30G,過了一會又下降了幾個G,毫無疑問,程序中有什么集合或者什么操作占用了大量內(nèi)存,所以準備在28,29G的時候抓dump分析分析。

二:解決思路

從快照中找問題就像看病一樣,根據(jù)病象猜測,都有一套經(jīng)驗可循。

1. 把托管堆中>10M的對象找出來

通常應(yīng)對大集合從托管堆入手最簡單,看哪個類型占用空間大,基本就是它出問題了,為了避免把所有類型都打出來,這里設(shè)置一下過濾,把小于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. 找出堆中可疑的對象

因為程序啟動后作為內(nèi)存數(shù)據(jù)庫,所以有包含指定類的大集合對象很正常,倒數(shù)第7行有一個Dictionary<int,Datetime> 占用空間挺大的,1128274800/1024/1024=1G,這個貌似不是基礎(chǔ)數(shù)據(jù),應(yīng)該是中間變量,方法表地址為00007ffe094baf50, 通過它可以找到這68個集合的內(nèi)存地址。


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 找到它的引用根,通過引用鏈就可以找到它的代碼區(qū)塊,簡直不要太實用


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> 當(dāng)前字典在 2da8 線程上

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

<3> 調(diào)用鏈頂部是最大的集合 Dictionary<string,Ditionary<int,DateTime>> ,address:000001c3d5c1bdf0

4. 尋找更多信息

<1> 挖字典內(nèi)容

有了最大的字典,我們來看看最大字典Dictionary<string,Ditionary<int,DateTime>> 占用的內(nèi)存大小。


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]])

根據(jù)sizeof(000001c3d5c1bdf0) = 340008256 (0x14441d40) bytes 計算一下:324M,尼瑪,這都是其中一個字典,難怪內(nèi)存忽高忽低,現(xiàn)在大家肯定特別想知道里面有啥東西,可以用 da -> !do 去內(nèi)部集合看一下。


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] 000001c3d8de7d38
   Name:        System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[System.DateTime, mscorlib]], mscorlib]]
   MethodTable: 00007ffdab940520
   EEClass:     00007ffe08e92920
   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
       00007ffe094e9288  4003474       10             System.Int32      1     instance             58671583     hashCode
       00007ffe094e9288  4003475       14             System.Int32      1     instance                   -1     next
       00007ffe094ebf10  4003476        0           System.__Canon      0     instance     000001c2cec43610     key
       00007ffe094ebf10  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個元素,然后我挑了一個內(nèi)嵌Dictionary,可以看到這個內(nèi)嵌字典的count=251w,里面的details我就不輸出了。

<2> 挖線程棧

有了字典內(nèi)容,大家繼續(xù)看一下此時這個線程 [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
00000017f4c7e388 00007ffe28646124 [HelperMethodFrame: 00000017f4c7e388]
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)

Android程序內(nèi)存忽高忽低怎么解決

大家應(yīng)該知道,有擴容就有虛占內(nèi)存。

“Android程序內(nèi)存忽高忽低怎么解決”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI