天天看點

HaaS100開發調試系列 之 定位AliOS Things記憶體及Crash問題1、先抛出問題2、打開相關元件3、記憶體CLI指令3.1、記憶體狀态查詢3.2、記憶體log dump4、檢視記憶體的API接口5、記憶體log解析工具的使用6、小結

這是《HaaS100開發調試系列》第5篇,建議讀者把前面幾篇快速浏覽一下,可以幫助大家盡快上手AliOS Things的開發調試。連結是: 一文輕松入門HaaS100診斷調試系統 HaaS100開發調試系列 之 如何使用J-Link仿真器調試代碼 HaaS100 開發調試系列 之 CPU使用率(cpuusage)的原理與使用 HaaS100開發調試系列 之 使用AliOS Things診斷調試元件定位Bug 本文主要說開發調試過程中經常遇到的記憶體問題。

1、先抛出問題

在開發過程中,我們總是會遇到諸如:

  • 系統總記憶體怎麼查詢?
  • 系統剩餘可用記憶體還有多少呢,我的應用需要malloc 100KB空間,能成功嗎?
  • 查詢到的系統可用記憶體還有200KB,為什麼我連50KB都申請不到了呢?
  • 系統跑着跑着,就會産生異常crash而當機了,查到原因是系統動态記憶體耗盡了,即出現了典型的記憶體洩漏,這個時候應該從哪着手查起呢?

上述的記憶體問題總是讓人頭痛,是以AliOS Things給大家提供了一套強大的記憶體問題分析定位方法,即:

  • 記憶體查詢專用的CLI指令
  • 記憶體查詢API接口
  • 記憶體log解析工具
  • 記憶體dump機制
  • 記憶體解析工具

結合這四種方法,我們希望盡可能給開發者提供系統記憶體分析,幫助開發者進一步定位記憶體問題。

2、打開相關元件

記憶體問題分析,依賴AliOS Things提供的cli元件和debug元件。打開步驟如下:

step1

在package.yaml 檔案裡添加 cli元件和debug元件。

舉例說明,我們目前使用的是helloworld_demo,那我們進入solution/helloworld_demo/package.yaml,增加:

depends:
 
- cli: rel_3.3.0    # helloworld_demo中添加cli元件
 
- debug: rel_3.3.0  # helloworld_demo中添加debug元件           

Step2

使能記憶體調試宏RHINO_CONFIG_MM_DEBUG,方法是在 solution/helloworld_demo/package.yaml裡增加

def_config:                              # 元件的可配置項
 
    RHINO_CONFIG_MM_DEBUG: 1           

Step3

重新編譯燒錄闆子,參考

HaaS100快速開始

Step4

上電後系統啟動後,執行help看一下,系統自帶了一些調試指令。

HaaS100開發調試系列 之 定位AliOS Things記憶體及Crash問題1、先抛出問題2、打開相關元件3、記憶體CLI指令3.1、記憶體狀态查詢3.2、記憶體log dump4、檢視記憶體的API接口5、記憶體log解析工具的使用6、小結

3、記憶體CLI指令

3.1、記憶體狀态查詢

執行dumpsys mm 檢視系統記憶體狀态,會有下面的列印輸出(舉例):

dumpsys mm           
HaaS100開發調試系列 之 定位AliOS Things記憶體及Crash問題1、先抛出問題2、打開相關元件3、記憶體CLI指令3.1、記憶體狀态查詢3.2、記憶體log dump4、檢視記憶體的API接口5、記憶體log解析工具的使用6、小結

字段解釋

HEAP中的内容含義(機關為位元組):

  • TotalSz:系統可供malloc的動态記憶體總大小;
  • FreeSz:系統目前空閑記憶體大小;
  • UsedSz:系統目前已經配置設定的記憶體大小,即UsedSz = TotalSz – FreeSz;
  • MinFreeSz:系統空閑記憶體的曆史最小值,即TotalSz – MinFreeSz 便是記憶體曆史使用量峰值;
  • MaxFreeBlkSz:系統最大空閑塊Size,表示系統此時可供配置設定出來的記憶體最大值。

上面各字段就可以回答本文開頭的一些問題:

“系統總記憶體怎麼查詢”—— TotalSz

“系統剩餘可用記憶體”—— FreeSz

“查詢到的系統可用記憶體還有200KB,為什麼我連50KB都申請不到了呢?” —— 檢視MaxFreeBlkSz,這個字段表示系統此時可供配置設定出來的記憶體最大值。如果系統存在大量小記憶體(如size低于256位元組的記憶體)不斷malloc和free的情況,系統會産生一些記憶體碎片,這個時候即使系統可用記憶體(FreeSz)還夠,也隻能最大配置設定出MaxFreeBlkSz的記憶體。關于AliOS Things使用的記憶體算法和對記憶體碎片的處理,請讀者關注我們後續的文章。

3.2、記憶體log dump

執行dumpsys mm_info 可将系統的詳細動态記憶體資訊dump出來,如果系統有很多的記憶體malloc,這一步可能會dump的時間比較久,示例如下:

dumpsys mm_info           
------------------------------- all memory blocks ---------------------------------
 
g_kmm_head = 34002240
 
ALL BLOCKS
 
address,  stat   size     dye     caller   pre-stat    point
 
0x34002318  used       8  fefefefe  0x0        pre-used;
 
0x34002330  used      32  fefefefe  0x229ad7   pre-used;
 
0x34002360  used      32  fefefefe  0x22b5cf   pre-used;
 
0x34002390  used      40  fefefefe  0x22d14f   pre-used;
 
0x340023c8  used      32  fefefefe  0x208e03   pre-used;
 
0x340023f8  used      40  fefefefe  0x22c3af   pre-used;
 
0x34002430  used      40  fefefefe  0x22c3af   pre-used;
 
0x34002468  used      40  fefefefe  0x22d14f   pre-used;
 
0x340024a0  used      32  fefefefe  0x229ad7   pre-used;
 
0x340024d0  used      32  fefefefe  0x22b5cf   pre-used;
 
0x34002500  used      80  fefefefe  0x207b67   pre-used;
 
0x34002560  used      32  fefefefe  0x229ad7   pre-used;
 
0x34002590  used      32  fefefefe  0x22b5cf   pre-used;
 
0x340025c0  used      40  fefefefe  0x22d14f   pre-used;
 
0x340025f8  used      32  fefefefe  0x229ad7   pre-used;
 
0x34002628  used      32  fefefefe  0x22b5cf   pre-used;
 
0x34002658  used  131072  fefefefe  0x22d865   pre-used;
 
0x34022668  used     200  fefefefe  0x22d86f   pre-used;
 
0x34022740  used    2048  fefefefe  0x1c5d8979 pre-used;
 
0x34022f50  used      40  fefefefe  0x1c5ddc59 pre-used;
 
0x34022f88  used     800  fefefefe  0x1c5d671b pre-used;
 
0x340232b8  used    8192  fefefefe  0x22d865   pre-used;
 
0x340252c8  used     200  fefefefe  0x22d86f   pre-used;
 
0x340253a0  used      32  fefefefe  0x1c5d9055 pre-used;
 
0x340253d0  used      40  fefefefe  0x1c5d5cf9 pre-used;
 
0x34025408  used    5120  fefefefe  0x1c5dd8fd pre-used;
 
0x34026818  used      80  fefefefe  0x1c5d5da7 pre-used;
 
0x34026878  used    3072  fefefefe  0x22d865   pre-used;
 
0x34027488  used     200  fefefefe  0x22d86f   pre-used;
 
0x34027560  used      40  fefefefe  0x1c5d7901 pre-used;
 
0x34027598  used      40  fefefefe  0x1c5d7935 pre-used;
 
0x340275d0  used      40  fefefefe  0x22c3af   pre-used;
 
0x34027608  used      32  fefefefe  0x1c5dde4f pre-used;
 
0x34027638  used      32  fefefefe  0x1c5d90e7 pre-used;
 
0x34027668  used      40  fefefefe  0x1c5d8e03 pre-used;
 
0x340276a0  used      40  fefefefe  0x1c5d5cf9 pre-used;
 
0x340276d8  used      32  fefefefe  0x1c5d9161 pre-used;
 
0x34027708  used      32  fefefefe  0x1c5d916b pre-used;
 
0x34027738  used     432  fefefefe  0x2078a7   pre-used;
 
0x340278f8  used    1024  fefefefe  0x207dc7   pre-used;
 
0x34027d08  used     512  fefefefe  0x1c5d6251 pre-used;
 
0x34027f18  free  6660872  abababab  0x0        pre-used; free[(nil)   ,(nil)   ]
 
0x34682230  used  sentinel  fefefefe  0x0        pre-free [0x34027f18];
 
 
 
----------------------------- all free memory blocks -------------------------------
 
freelist bitmap: 0x20000
 
address,  stat   size     dye     caller   pre-stat    point
 
0x34027f18  free  6660872  abababab  0x0        pre-used; free[(nil)   ,(nil)   ]
 
 
 
------------------------- memory allocation statistic ------------------------------
 
---------------------------------------------------------------------------
 
[HEAP]| TotalSz    | FreeSz     | UsedSz     | MinFreeSz  | MaxFreeBlkSz  |
 
      | 0x00680000 | 0x0065A308 | 0x00025CF8 | 0x0065A0F8 | 0x0065A308    |
 
---------------------------------------------------------------------------
 
 
 
-----------------number of alloc times:-----------------
 
[2^06] bytes:    33   |[2^07] bytes:     1   |[2^08] bytes:     3   |[2^09] bytes:     1   |
 
[2^10] bytes:   987   |[2^11] bytes:     1   |[2^12] bytes:     2   |[2^13] bytes:     1   |
 
[2^14] bytes:     1   |[2^15] bytes:     0   |[2^16] bytes:     0   |[2^17] bytes:     0   |
 
[2^18] bytes:     1   |[2^19] bytes:     0   |[2^20] bytes:     0   |[2^21] bytes:     0   |
 
[2^22] bytes:     0   |[2^23] bytes:     0   |[2^24] bytes:     0   |[2^25] bytes:     0   |
 
[2^26] bytes:     0   |[2^27] bytes:     0   |[2^28] bytes:     0   |[2^29] bytes:     0   |           

重點關注的是“ all memory blocks”下面的log,其中幾個關鍵的字段含義為:

  • address:使用者malloc後,系統配置設定出來的位址,即malloc的傳回值
  • stat: 記憶體狀态,used表示malloc後記憶體還在使用,free表示這塊記憶體已經釋放
  • size:malloc的大小(機關:位元組)
  • caller:調用malloc的地方,即這塊記憶體的使用者是誰。
  • dye/pre-stat:AliOS Things使用的記憶體管理算法相關,這裡不贅述。

4、檢視記憶體的API接口

如果需要在代碼中調用記憶體狀态查詢,AliOS Things也提供了如下API接口,該接口的輸出與上述執行dumpsys mm的輸出一緻。

//需要包含的頭檔案

#include "aos/debug.h"           

//接口調用方法

aos_debug_mm_overview(NULL)           

5、記憶體log解析工具的使用

面對上面dumpsys mm_info指令輸出的這麼多log,我們怎麼分析呢?

配合解析腳本 coredump_parser.py, 我們可以得到下面的結果:

========== Show MM Statistic Info  ==========
 
--------------------------------------------------------------------------------------------------------------------------------------------------------------
 
 Alloc Addr  |           Func           | Cnt  |  Total Size  |   Line   |       File     
 
--------------------------------------------------------------------------------------------------------------------------------------------------------------
 
  0x208e03   |          srand           |  1   |      32      |          |     reent.c    
 
 0x1c5d9055  | aos_register_event_filter |  1   |      32      |   131    | /workspace/hass/AliOS-Things/components/utility/yloop/src/local_event.c
 
 0x1c5dde4f  |    vfs_inode_set_name    |  1   |      32      |    25    | /workspace/hass/AliOS-Things/core/vfs/vfs_inode.c
 
 0x1c5d90e7  |      aos_loop_init       |  1   |      32      |    85    | /workspace/hass/AliOS-Things/components/utility/yloop/src/yloop.c
 
 0x1c5d9161  |     aos_poll_read_fd     |  1   |      32      |   113    | /workspace/hass/AliOS-Things/components/utility/yloop/src/yloop.c
 
 0x1c5d916b  |     aos_poll_read_fd     |  1   |      32      |   114    | /workspace/hass/AliOS-Things/components/utility/yloop/src/yloop.c
 
 0x1c5ddc59  |     vfs_lock_create      |  1   |      40      |    17    | /workspace/hass/AliOS-Things/core/vfs/vfs_adapt.c
 
 0x1c5d7901  |      kv_lock_create      |  1   |      40      |    33    | /workspace/hass/AliOS-Things/core/kv/kv_adapt.c
 
 0x1c5d7935  |      kv_sem_create       |  1   |      40      |    82    | /workspace/hass/AliOS-Things/core/kv/kv_adapt.c
 
 0x1c5d8e03  |        event_open        |  1   |      40      |    40    | /workspace/hass/AliOS-Things/components/utility/yloop/src/device.c
 
  0x207b67   |        localtime         |  1   |      80      |          |     reent.c     
 
 0x1c5d5cf9  |      aos_mutex_new       |  2   |      80      |   147    | /workspace/hass/AliOS-Things/core/osal/aos/rhino.c
 
 0x1c5d5da7  |      aos_queue_new       |  1   |      80      |   349    | /workspace/hass/AliOS-Things/core/osal/aos/rhino.c
 
  0x22d14f   |  krhino_sem_dyn_create   |  3   |     120      |   102    | /workspace/hass/AliOS-Things/core/rhino/k_sem.c
 
  0x22c3af   | krhino_mutex_dyn_create  |  3   |     120      |   125    | /workspace/hass/AliOS-Things/core/rhino/k_mutex.c
 
  0x229ad7   |      osThreadCreate      |  4   |     128      |   250    | /home/william.wgj/work/code/shenmu_lite/shenmu_github/shenmu_aos/platform/mcu/haas1000
 
                                                                           /drivers/out/haas1000_normalization/../../rtos/rhino/cmsis/cmsis_os.c
 
  0x22b5cf   | krhino_event_dyn_create  |  4   |     128      |   102    | /workspace/hass/AliOS-Things/core/rhino/k_event.c
 
  0x2078a7   |       __sfmoreglue       |  1   |     432      |          |     reent.c     
 
 0x1c5d6251  |       proc_onecmd        |  1   |     512      |   156    | /workspace/hass/AliOS-Things/core/cli/cli.c
 
  0x22d86f   |     task_dyn_create      |  3   |     600      |   280    | /workspace/hass/AliOS-Things/core/rhino/k_task.c
 
 0x1c5d671b  |         cli_init         |  1   |     800      |   697    | /workspace/hass/AliOS-Things/core/cli/cli.c
 
  0x207dc7   |       __smakebuf_r       |  1   |     1024     |          |     reent.c    
 
 0x1c5d8979  |      hal_uart_init       |  1   |     2048     |   333    | /workspace/hass/AliOS-Things/platform/mcu/haas1000/hal/uart.c
 
 0x1c5dd8fd  |     uring_fifo_init      |  1   |     5120     |    25    | /workspace/hass/AliOS-Things/components/dm/ulog/ulog_ring_fifo.c
 
  0x22d865   |     task_dyn_create      |  3   |    142336    |   275    | /workspace/hass/AliOS-Things/core/rhino/k_task.c
 
--------------------------------------------------------------------------------------------------------------------------------------------------------------           

使用方法

  1. 将序列槽輸出的異常log 拷貝至coredump_parser.py的同級目錄中,檔案名任意,這裡取名為log,coredump_parser.py路徑為: https://github.com/alibaba/AliOS-Things/tree/dev_3.1.0_haas/components/utility/debug_tools
  2. 将編譯生成的elf檔案(aos.elf)也拷貝至coredump_parser.py的同級目錄,elf 路徑為solutions/helloworld_demo/out/helloworld_demo/aos.elf
  3. 執行下面指令(舉例)
python coredump_parser.py log aos.elf           

如果系統提示如“arm-none-eabi-gcc”找不到,表示使用的工具鍊沒有在系統PATH下,

arm-none-eabi-gcc在 AliOS Things代碼下載下傳時自帶的工具鍊toolchian裡,toolchian路徑為:

~/.aliot/arm-none-eabi/main/bin

可以将這個路徑添加到系統PATH路徑下,也可以使用-p參數,如

python coredump_parser.py log aos.elf -p  ~/.aliot/arm-none-eabi/main/bin           

這個工具會将系統記憶體malloc情況輸出到表格中,并且按照Total Size從小到大排序,同時指出了每個記憶體塊的申請者caller在代碼中的位置,一目了然。如果開發者定位或者懷疑此時系統内出現了記憶體洩漏,那麼經過上面的解析出的系統記憶體使用,我們可以直接看出哪個子產品的記憶體隻有申請沒有釋放了,一般是Total Size 最大的那個點!

6、小結

系統記憶體問題的定位比較複雜,使用上面幾個方法,可以有效的幫助開發者定位排查一些記憶體問題,希望大家多多嘗試上面的指令,靈活使用,才能發揮出AliOS Things的診斷調試的強大功能。

開發者支援

HaaS解決方案中心:

https://haas.iot.aliyun.com/

HaaS技術社群:

https://blog.csdn.net/HaaSTech

開發者釘釘群和公衆号見下圖,開發者釘釘群每天都有技術支援同學值班。

HaaS100開發調試系列 之 定位AliOS Things記憶體及Crash問題1、先抛出問題2、打開相關元件3、記憶體CLI指令3.1、記憶體狀态查詢3.2、記憶體log dump4、檢視記憶體的API接口5、記憶體log解析工具的使用6、小結