android 記憶體流失問題【轉】

來源:互聯網
上載者:User

標籤:res   limits   dia   idp   run   nmap   padding   啟動   vss   

本文轉載自:http://www.voidcn.com/article/p-hbnuyfwz-ee.html

記憶體泄露問題在一些壓力測試的情境很容易暴露,例如一些常用應用情境反覆操作(eg:反覆切換前後網路攝影機,反覆進入退出相機應用、壓力拍照等等)。

記憶體泄露一般表現為:

①記憶體配置釋放,導致進程空間虛擬位址被分配完,或者物理地址被分配完。

②檔案泄露,導致進程空間檔案控制代碼數達到最大值。

③線程泄露,導致進程空間虛擬位址被分配完,進程內保留很多線程棧(stack)。

 

 

Android Native層中大部分的泄露問題都在HAL層,主要導致原因就是一些非對稱操作。

1. 工具

 

這一層主要使用工具為Linux內建的工具以及一些檔案節點的狀態。

命令列表:

ps  [-t] [pid] [ | busybox wc -l ]

top [-t]

ll /proc/pid/fd [ |busybox wc -l ]

cat /proc/pid/maps [ |busybox wc -l ]

cat /proc/meminfo [ | grep "MemFree" ]

dumpsys meminfo [ pid ] [ package name ]

procrank valgrind

valgrind

 

 

2. ps / top命令

 

ps /top 可以對linux系統中進程進行監測和控制。Ps 是顯示瞬間進程的狀態;Top是對進程已耗用時間監控。

Ps/top命令尋找到目標的進程號pid,再根據pid去觀測反覆操作中Ps/top的兩項列印項:

VSIZE(VSS)  :佔用的虛擬記憶體的大小。

RSS :佔用記憶體的大小。

確認下這兩項是否一直在無限制增大,這樣子可以初步確認一下記憶體泄露問題的存在性。

ps -t pid 這個命令可以列出當前進程所有線程,包括native線程和java線程。

native線程可以查看到其線程名,如:

USER     PID   PPID  VSIZE  RSS     WCHAN    PC         NAME

media     1574  1465    50312  9992   c0089920   b6ea491c SCameraCaptureTh

 

Java 線程只能看到java線程在native層的映射名

USER     PID   PPID  VSIZE  RSS  WCHAN   PC       NAME

u0_a22    6884  2562  984204 54004 c0089920  4010491c SThread-194

 

查線程是否泄露技巧:可以在相同的狀態反覆使用下面命令,如在每次應用開啟關閉後使用,這個命令可以統計目標進程內所有的線程數,這個數一直在增加的話,說明進程記憶體在進程內有線程沒有正常被釋放。

ps -t pid | busybox wc -c

 

 

3. proc進程狀態節點 

 

Linux proc虛擬檔案系統中會記載系統所有進程的一些狀態資訊,在/prco下會有進程目錄,目錄名就是pid。pid檔案夾下資訊量非常龐大,現在只介紹兩個與查內泄漏相關的:fd目錄和maps節點。

[email protected]:/ # ps mediaserver

USER     PID   PPID  VSIZE  RSS   WCHAN    PC         NAME

media     8403  1     240688   16940  ffffffff  b6f225a0 S /system/bin/mediaserver

[email protected]:/ # ll /proc/8403

 

dr-xr-xr-x media    audio             2012-02-14 12:55 attr

.......................................

dr-x------ media    audio             2012-02-14 12:55 fd

-r--r--r-- media     audio           0 2012-02-14 12:55 maps

.......................................

-r--r--r-- media    audio           0 2012-02-14 12:55 wchan

 

①進程fd目錄

可以看出fd目下為檔案控制代碼的連結,例如17為檔案控制代碼號,/system/etc/camera.cfg為開啟的檔案目錄。

[email protected]:/ # ll /proc/8403/fd

 

lrwx------ media    audio             2012-02-14 13:02 0 -> /dev/null

lrwx------ media    audio             2012-02-14 13:02 1 -> /dev/null

l-wx------ media    audio             2012-02-14 13:02 10 -> /dev/log/system

lr-x------ media    audio             2012-02-14 13:02 11 -> /dev/__properties__

lr-x------ media    audio             2012-02-14 13:02 16 -> /system/etc/camera.cfg

lr-x------ media    audio             2012-02-14 13:0217 -> /system/etc/camera.cfg

l-wx------ media    audio             2012-02-14 13:02 18 -> /dev/cpuctl/apps/tasks

lrwx------ media    audio             2012-02-14 13:02 3 -> /dev/binder

lrwx------ media    audio             2012-02-14 13:02 8 -> /dev/cpuctl/tasks

l-wx------ media    audio             2012-02-14 13:02 9 -> /dev/log/events

.......................................

 

查看系統每個線程的檔案控制代碼最大值,一般系統都會預設一個進程最多有1024個檔案控制代碼,當一個進程開啟檔案控制代碼的數量達到1024時,再次建立檔案控制代碼會失敗,strerror(errno)會報出“Too many open files”。

cat /proc/pid/limits  |  grep "Max open files"

 

查檔案控制代碼是否泄露技巧:可以在相同的狀態反覆使用下面命令,如在每次應用開啟關閉後使用,這個命令可以統計目標進程內所有檔案控制代碼,這個數一直在增加的話,說明進程記憶體在進程內有檔案控制代碼沒有正常被關閉。

cat /proc/fd | busybox wc -c

 

②進程maps節點

Maps節點可以查詢進程的虛記憶體空間的使用方式。

 

該檔案有6列,分別為:

地址:庫在進程裡位址範圍

許可權:虛擬記憶體的許可權,r=讀,w=寫,x=,s=共用,p=私人;

位移量:庫在進程裡位址範圍

裝置:映像檔案的主裝置號和次裝置號;

節點:映像檔案的節點號;

路徑: 映像檔案的路徑

[email protected]:/ # cat /proc/8403/maps

 

a9035000-a9525000 rw-s 98bb3000 00:09 2159       anon_inode:dmabuf

................................................................

a95bf000-a96bc000 rw-p 00000000 00:00 0          [stack:11334]

a99fc000-ab17b000 rw-s 96354000 00:0c 31508      /dev/video0

ab17b000-ac8fa000 rw-s 94bd5000 00:0c 31508      /dev/video0

af7f8000-b0f77000 rw-s 90558000 00:0c 31508      /dev/video0

b0f77000-b26f6000 rw-s 8edd9000 00:0c 31508      /dev/video0

................................................................

 

b26f9000-b27f6000 rw-p 00000000 00:00 0          [stack:11307]

b27f6000-b27f8000 rw-p 00000000 00:00 0

................................................................

b4bb4000-b4bb5000 r--p 00001000 b3:07 1091       /system/lib/libril_audio.so

b4bb5000-b4bb6000 rw-p 00002000 b3:07 1091       /system/lib/libril_audio.so

..................................................................

b6f54000-b6f55000 r--p 0000f000 b3:07 149        /system/bin/linker

b6f55000-b6f56000 rw-p 00010000 b3:07 149        /system/bin/linker

b6f56000-b6f57000 rw-p 00000000 00:00 0

b6f57000-b6f59000 r-xp 00000000 b3:07 162        /system/bin/mediaserver

b6f5a000-b6f5b000 r--p 00002000 b3:07 162        /system/bin/mediaserver

b6f5b000-b6f5c000 rw-p 00000000 00:00 0

b852b000-b859d000 rw-p 00000000 00:00 0          [heap]

bea7c000-bea9d000 rw-p 00000000 00:00 0          [stack]

ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]

 

 

32位Liunx系統每個進程有4G地址空間,android系統下進程地址空間分部如下:

                                                                                                           

高位1G空間為核心地址空間,地位3G空間為使用者地址空間,可以看出棧stack是有高位向低位增長,而堆heap是由地位向高位增長,還有一段載入動態庫的段,可以根據上面的catmaps列印出來對比。

堆泄露的定位方法:

下面是調用mmap映射得到進程虛擬位址,這樣的列印持續增多的話,說明進程中有mmap 和 munmap沒有對稱操作,導致進程虛擬位址的泄露。

ab17b000-ac8fa000 rw-s 94bd5000 00:0c 31508      /dev/video0

 

下面是一個線程棧的使用方式, [stack:11334],11334為線程號tid,這樣的列印持續增多的話,說明進程中會持續建立線程,但是沒有釋放舊線程。

a95bf000-a96bc000 rw-p 00000000 00:00 0          [stack:11334]

 

 

③meminfo節點

proc/meminfo節點記錄了系統記憶體的一些使用方式,主要看MemFree這項。

[email protected]:/ # cat /proc/meminfo

cat /proc/meminfo

MemTotal:        1673008 kB所有可用RAM大小(即實體記憶體減去一些預留位和核心的二進位代碼大小)

MemFree:          761320 kB  LowFree與HighFree的總和,被系統留著未使用的記憶體

..........................................

Mapped:            87932 kB 裝置和檔案等映射的大小。

..........................................

 

 

4. Android 工具

 

這是Android上實現的一些命令,在Native這層也可以使用,但是統計的一些資訊也和上面的一樣。

①dumpsys meminfo [ pid ] [ package name]

可以查看到某個線程(包括應用應用和系統線程)記憶體使用量情況,包括Native堆和java堆。一般用來查java應用的進程,對於系統Native進程,dump出來資訊較少。

 

②procrank

Androidprocrank  (/system/xbin/procrank) 工具,能夠列出進程所佔用的記憶體使用量情況。順序為從高到低。每個進程佔用記憶體大小以 VSS,  RSS , PSS, USS 的形式列出。為了簡化描述,記憶體佔用以頁為單位表述,而不是位元組。 通常每頁為 4096 位元組。(和ps功能差不多,資料有少許差異)。

 

③valgrind

android sdk預設整合了valgrind,一款優秀的記憶體問題偵查工具,能夠發現記憶體流失。

當前的方案預設沒有編譯該工具,可以通過以下命令臨時編譯:

$ cd external/valgrind

$ mm -j16

然後回到android根目錄編譯生產system.img。對於系統啟動啟動並執行進程需要,如debug surfaceflinger,需要在init.rc注釋surfaceflinger service,改為命令列啟動,

[email protected]:/ # valgrind --leak-check=full --log-file=/data/valgrind.log /system/bin/surfaceflinger &

 

進行介面的一些簡單操作後將surfacelinger進程kill掉,valgrind即會將分析報告輸出到/data/valgrind.log,裡面資訊很多,附上相關的範例log:

 

關注leak summary:

 

==1982== LEAK SUMMARY:

==1982==    definitely lost: 58,004 bytes in 477 blocks

==1982==    indirectly lost: 376 bytes in 8 blocks

==1982==      possibly lost: 122,997 bytes in 484 blocks

==1982==    still reachable: 922,973 bytes in 20,141 blocks

==1982==         suppressed: 0 bytes in 0 blocks

==1982== Reachable blocks (those to which a pointer was found) are not shown.

==1982== To see them, rerun with: --leak-check=full --show-reachable=yes

==1982==

==1982== For counts of detected and suppressed errors, rerun with: -v

==1982== Use --track-origins=yes to see where uninitialised values come from

==1982== ERROR SUMMARY: 673822 errors from 827 contexts (suppressed: 0 from 0)

 

 

android 記憶體流失問題【轉】

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.