我想寫一些單元測試,檢查內存是否已被釋放 - 檢查內存泄漏 - 在OS X(10.9小牛)上。我試圖使用mstats()和malloc_zone_statistics()來發現我需要的信息。但似乎他們不顯示內存被釋放(見下面的示例輸出...內存使用免費後不會改變()被調用)爲什麼mstats和malloc_zone_statistics在空閒後不顯示恢復的內存?
我懷疑這比具有更多的是與堆管理這些功能的問題。我認爲這堆並不釋放釋放的內存,也許它可以在沒有刪除和添加塊的開銷的情況下重用它。
- 有沒有辦法告訴堆釋放釋放塊?要更積極或關閉優化?
- 我只是不正確地使用mstats()或malloc_zone_statistics()?
更新:溶液中發現的......在底部提供...
這裏是我的測試程序的輸出:
=== Initial conditions ===
in use: 23584, allocated: 9437184, blocks: 320
SimpleLeaker(19583,0x7fff7b2a2310) malloc: total: 9437184, used: 23584, free: 9413600
=== Before allocation ===
in use: 23584, allocated: 9437184, blocks: 320
SimpleLeaker(19583,0x7fff7b2a2310) malloc: total: 9437184, used: 23584, free: 9413600
=== After malloc ===
in use: 33824, allocated: 9437184, blocks: 321
SimpleLeaker(19583,0x7fff7b2a2310) malloc: total: 9437184, used: 33824, free: 9403360
=== After free ===
in use: 33824, allocated: 9437184, blocks: 321
SimpleLeaker(19583,0x7fff7b2a2310) malloc: total: 9437184, used: 33824, free: 9403360
這裏是爲C代碼程序:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <mach/mach.h>
#include <mach/task.h>
#include <malloc/malloc.h>
#include <errno.h>
/** heapStats()
* print the output from the mstats() function: total heap bytes,
* used bytes, and free bytes.
*/
void heapStats()
{
struct mstats ms = mstats();
malloc_printf(
"total: %d, used: %d, free: %d\n",
ms.bytes_total,
ms.bytes_used,
ms.bytes_free);
}
/* heapInUse()
* Gather the heap usage metrics from each zone, using
* malloc_zone_statistics().
*/
void heapInUse(
size_t * bytesInUse,
size_t * blocksInUse,
size_t * sizeAllocated)
{
*bytesInUse = 0;
*blocksInUse = 0;
*sizeAllocated = 0;
unsigned int i;
vm_address_t * zones;
unsigned int count;
kern_return_t rc =
malloc_get_all_zones(mach_task_self(), 0, &zones, &count);
if (0 != rc)
{
fprintf(stderr, "rc was %d\n", rc);
}
for (i = 0; i < count; ++i)
{
malloc_zone_t * zone = (malloc_zone_t*)zones[i];
char const * name = malloc_get_zone_name(zone);
if (NULL == name)
{
continue;
}
malloc_statistics_t stats;
stats.blocks_in_use = 0;
stats.size_in_use = 0;
stats.max_size_in_use = 0;
stats.size_allocated = 0;
malloc_zone_statistics(zone, &stats);
*bytesInUse += stats.size_in_use;
*blocksInUse += stats.blocks_in_use;
*sizeAllocated += stats.size_allocated;
}
}
/** main()
* entry point
*/
int main(int argc, const char * argv[])
{
char * buff = (char *)0;
size_t bytesInUse = 0;
size_t blocksInUse = 0;
size_t sizeAllocated = 0;
printf("=== Initial conditions ===\n");
heapInUse(&bytesInUse, &blocksInUse, &sizeAllocated);
printf(
"in use: %zu, allocated: %zu, blocks: %zu\n",
bytesInUse, sizeAllocated, blocksInUse);
heapStats();
printf("=== Before allocation ===\n");
heapInUse(&bytesInUse, &blocksInUse, &sizeAllocated);
printf(
"in use: %zu, allocated: %zu, blocks: %zu\n",
bytesInUse, sizeAllocated, blocksInUse);
heapStats();
// Allocate the buffer
//
buff = (char *)malloc(10000);
printf("=== After malloc ===\n");
heapInUse(&bytesInUse, &blocksInUse, &sizeAllocated);
printf(
"in use: %zu, allocated: %zu, blocks: %zu\n",
bytesInUse, sizeAllocated, blocksInUse);
heapStats();
// Free the buffer
//
if (NULL != buff)
{
free(buff);
buff = NULL;
}
printf("=== After free ===\n");
heapInUse(&bytesInUse, &blocksInUse, &sizeAllocated);
printf(
"in use: %zu, allocated: %zu, blocks: %zu\n",
bytesInUse, sizeAllocated, blocksInUse);
heapStats();
// Get out
//
return 0;
}
解決方案:感謝ŧ Ø從John Zwinck響應我接過仔細看看malloc/malloc.h
,發現了一個方法malloc_zone_pressure_relief()
,我可以使用強制堆釋放未使用的字節,這樣我可以得到準確的指標。
所以我加入這個方法:
void freeAsMuchAsPossible()
{
vm_address_t * zones;
unsigned int count;
unsigned int i;
kern_return_t rc =
malloc_get_all_zones(mach_task_self(), 0, &zones, &count);
if (0 != rc)
{
fprintf(stderr, "rc was %d\n", rc);
}
for (i = 0; i < count; ++i)
{
malloc_zone_t * zone = (malloc_zone_t*)zones[i];
char const * name = malloc_get_zone_name(zone);
if (NULL == name)
{
continue;
}
malloc_zone_pressure_relief(zone, 0);
}
}
,並把它稱爲每次調用之前heapInUse()
,像這樣:
printf("=== Before allocation ===\n");
freeAsMuchAsPossible();
heapInUse(&bytesInUse, &blocksInUse, &sizeAllocated);
printf(
"in use: %zu, allocated: %zu, blocks: %zu\n",
bytesInUse, sizeAllocated, blocksInUse);
heapStats();
現在我得到預期的和有用的結果,例如:
=== Initial conditions ===
in use: 23584, allocated: 9437184, blocks: 4294966976
SimpleLeaker(22142,0x7fff7b2a2310) malloc: total: 9437184, used: 23584, free: 9413600
=== Before allocation ===
in use: 23584, allocated: 9437184, blocks: 4294966976
SimpleLeaker(22142,0x7fff7b2a2310) malloc: total: 9437184, used: 23584, free: 9413600
=== After malloc ===
in use: 33824, allocated: 9437184, blocks: 4294966967
SimpleLeaker(22142,0x7fff7b2a2310) malloc: total: 9437184, used: 33824, free: 9403360
=== After free ===
in use: 23584, allocated: 9437184, blocks: 4294966966
SimpleLeaker(22142,0x7fff7b2a2310) malloc: total: 9437184, used: 23584, free: 9413600
利用這種技術,我可以編寫單元測試,檢查內存泄漏。非常好。
'mallopt()'似乎是一個聰明的事情,並且將是在Linux系統上追求的一個很好的途徑。但是我正在使用OS X,'mallopt()'不可用,也許是因爲轉向了Clang。然而,這些建議讓我更加關注malloc.h,並且我發現了一個函數'malloc_zone_pressure_relief()',它似乎強制堆釋放未使用的字節。所以,謝謝你的推動。 – 2014-09-02 22:39:11