我想写一些单元测试,检查内存是否已被释放 - 检查内存泄漏 - 在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