文章首發於浩瀚先森博客
堆棧的概念在腦海里已經存在有一段時間了,今天就測試來整理下Heap堆。棧以后再說。
堆區不像全局變量和局部變量總是有指定的內存大小,它是為了在程序運行時動態分配內存而設定的一塊區域。
在程序運行時需要一塊特定大小的內存空間來使用的時候,那么可以先聲明空間大小值,然后在程序運行時會在某個區域里划分指定大小的內存空間出來,這里所說的某個區域就是堆區。
堆內存通常用類似malloc,free的函數來分配內存大小和釋放內存。
Malloc函數用來動態分配堆內存空間。成功分配空間后返回分配的內存地址指針。如果申請分配的空間大小大於堆的大小就返回NULL。
Free函數用來釋放先前分配的空間(創建堆空間后一定要記得釋放)。
動態分配內存的時候由於存在內存指針和內存大小的關系,可能會導致overhead,反復分配和注銷空間的話也會發生fragment問題.
實現動態分配內存的方法有很多種,在IAR Compiler里使用最多的是dlmalloc方法。
想要了解更多關於動態分配內存的可以點這里C dynamic memory allocation
看下面的例子

我們設定Heap的大小為512Byte,然后申請分配461byte空間。結果我們可以看到因為無法分配461Byte的空間導致返回NULL.
因為overhead導致最大只能使用460byte空間。
另外,由於overhead的原因,與一次性分配大空間內存相比,分多次來分配小一點內存空間,反而使我們能夠使用的總內存空間更少。
下面的例子是每次分配10byte,結果第30次的時候就無法再分配內存了。計算一下總共也只分配了290byte。

而在第一個例子里一次性分配大內存空間的時候最多反而可以分配460byte。
綜上所說與多次分配小內存相比,一次性分配大內存方式使得能使用的最大heap空間更多。
在寫嵌入式程序的時候,不像PC上內存資源豐富,嵌入式板子內存資源有限,必須准確的分配好heap堆的空間大小。然后預測一個程序要使用多少的heap空間,需要分配多大的heap並不是一件容易的事。
IAR EWARM提供能夠查詢堆使用量的函數。利用提供的函數我們就可以預測程序大概需要多大的heap空間。
下面介紹部分動態分配內存相關的庫函數
在使用IAR提供的庫函數之前需要進行下面的操作
在項目中添加IAR EWARM安裝目錄下的arm\src\lib\dlmalloc.c文件
NO_MALLINFO 設置為 0
NO_MALLOC_STATS設置為0
1. __iar_dlmalloc_stats
標准輸出(stdout)heap空間總大小以及heap使用量。

2. __iar_dlmallinfo
返回包含heap大小以及使用情況的結構體。

Mallinfo結構體信息參照下面內容。
#if !NO_MALLINFO
/*
mallinfo()
Returns (by copy) a struct containing various summary statistics:
arena: current total non-mmapped bytes allocated from system
ordblks: the number of free chunks
smblks: always zero.
hblks: current number of mmapped regions
hblkhd: total bytes held in mmapped regions
usmblks: the maximum total allocated space. This will be greater
than current total if trimming has occurred.
fsmblks: always zero
uordblks: current total allocated space (normal or mmapped)
fordblks: total free space
keepcost: the maximum number of bytes that could ideally be released
back to system via malloc_trim. ("ideally" means that
it ignores page restrictions etc.)
Because these fields are ints, but internal bookkeeping may
be kept as longs, the reported values may wrap around zero and
thus be inaccurate.
*/
struct mallinfo dlmallinfo(void);
#endif /* NO_MALLINFO */
更改heap堆大小
依照下面的方式可以設置使用heap堆的大小。
Heap堆大小在項目option的Linker選項里設置。
在Linker的Config里 點擊Edit來變更Linker的設置。

在Stack/Heap Sizes選項卡里變更heap堆大小。

分配的heap堆大小可以再map文件里查看確認。

