如何获取使用malloc()分配的内存块的大小?

时间:2009-07-30 19:01:45

标签: c++ c memory-management malloc

  

可能重复:
  How can I get the size of an array from a pointer in C?
  Is there any way to determine the size of a C++ array programmatically? And if not, why?

我从C样式函数中获取指向一块已分配内存的指针。 现在,调试目的非常有趣,知道如何 这个指针指向的已分配内存块很大。

有没有什么比通过盲目地跑过边界而引发异常更优雅?

提前致谢, 安德烈亚斯

编辑:

我在Windows上使用VC ++ 2005,在Linux上使用GCC 4.3

EDIT2:

我在VC ++ 2005下有_msize 不幸的是,它会在调试模式中导致异常....

EDIT3:

好。我尝试过上面描述的方式,但有效。 至少在我调试时并确保在通话结束后立即进行 到库出口我跑过缓冲区边界。像魅力一样。

它不优雅,在生产代码中无法使用。

9 个答案:

答案 0 :(得分:23)

这不是标准的,但如果你的图书馆有一个msize()函数可以给你大小。

一个常见的解决方案是使用您自己的函数来包装malloc,该函数记录每个请求以及大小和结果内存范围,在发布版本中您可以切换回“真实”malloc

答案 1 :(得分:12)

如果你为了调试而不介意低级暴力,你可以#define宏挂钩对malloc和free的调用,并用大小填充前4个字节。

调整

void *malloc_hook(size_t size) {
    size += sizeof (size_t);
    void *ptr = malloc(size);
    *(size_t *) ptr = size;
    return ((size_t *) ptr) + 1;
}

void free_hook (void *ptr) {
    ptr = (void *) (((size_t *) ptr) - 1);
    free(ptr);
}

size_t report_size(ptr) {
    return * (((size_t *) ptr) - 1);
}

然后

#define malloc(x) malloc_hook(x)

等等

答案 2 :(得分:10)

C运行时库不提供此类功能。此外,故意激发异常也不会告诉你这个块有多大。

通常,在C中解决此问题的方法是维护一个单独的变量,该变量跟踪分配的块的大小。当然,这有时不方便,但通常没有其他方法可以了解。

您的C运行时库可能提供一些可以查询已分配块的堆调试函数(毕竟,free()需要知道块有多大),但是这种类型的任何一种事情将是不可移植的。

答案 3 :(得分:5)

使用gccGNU linker,您可以轻松打包malloc

#include <stdlib.h>
#include <stdio.h>


void* __real_malloc(size_t sz);
void* __wrap_malloc(size_t sz)
{
    void *ptr;

    ptr = __real_malloc(sz);
    fprintf(stderr, "malloc of size %d yields pointer %p\n", sz, ptr);

    /* if you wish to save the pointer and the size to a data structure, 
       then remember to add wrap code for calloc, realloc and free */

    return ptr;
}

int main()
{
    char *x;
    x = malloc(103);

    return 0;
}

并使用

进行编译
gcc a.c -o a -Wall -Werror -Wl,--wrap=malloc

(当然,如果你愿意的话,这也适用于用g ++编译的c ++代码,以及new运算符(通过它的错位名称)。)

实际上,静态/动态加载的库也将使用您的__wrap_malloc

答案 4 :(得分:4)

不,除非在您的实施文档中,否则在超越其边界时不能依赖异常。这是你真正不需要知道编写程序的东西的一部分。如果您真的想知道,请深入了解编译器的文档或源代码。

答案 5 :(得分:4)

没有标准的C函数来执行此操作。根据您的平台,可能有一个不可移植的方法 - 您使用的操作系统和C库是什么?

请注意,引发异常是不可靠的 - 在您拥有的块之后可能会立即进行其他分配,因此在超出当前块的限制之后很久就不会出现异常。

答案 6 :(得分:4)

Valgrind's memcheckGoogle's TCMalloc(堆检查器部分)这样的内存检查程序可以跟踪这类事情。

您可以使用TCMalloc转储显示已分配内容的堆配置文件,或者您可以检查以确保使用SameHeap()在程序执行的两个点上堆相同。

答案 7 :(得分:2)

部分解决方案:在Windows上,您可以使用 PageHeap 来捕获已分配块之外的内存访问。

PageHeap是Windows内核中的备用内存管理器(在NT版本中,但现在没有人应该使用任何其他版本)。它会在进程中进行每次分配并返回一个内存块,该内存块的末尾与内存页面的末尾对齐,然后它使后续页面无法访问(无读取,无写入访问)。如果程序试图读取或写入块的末尾,您将获得一个访问冲突,您可以使用您喜欢的调试器。

如何获取:从Microsoft下载并安装适用于Windows的调试工具包:http://www.microsoft.com/whdc/devtools/debugging/default.mspx

然后启动GFlags实用程序,转到第3个选项卡并输入可执行文件的名称,然后按下该键。检查PageHeap复选框,单击OK,你就可以了。

最后一件事:当你完成调试时,不要忘记再次启动GFlags,并为应用程序禁用PageHeap。 GFlags将此设置输入注册表(在HKLM \ Software \ Microsoft \ Windows NT \ CurrentVersion \ Image File Execution Options \下),因此即使在重新启动时也是如此。

另外,请注意使用PageHeap可以极大地增加应用程序的内存需求。

答案 8 :(得分:1)

执行所需操作的方法是 BE 分配器。如果您筛选所有请求,然后将其记录以进行调试,那么您可以在内存空闲时找到所需内容。

此外,您可以在程序结束时检查是否已释放所有已分配的块,如果没有,则列出它们。这种雄心勃勃的图书馆甚至可以通过宏获取 FUNCTION LINE 参数,让您准确了解泄漏内存的位置。

最后,Microsoft的MSVCRT提供了一个可调试的堆,它有许多有用的工具,您可以在调试版中使用它们来查找内存问题:http://msdn.microsoft.com/en-us/library/bebs9zyz.aspx

在Linux上,您可以使用valgrind查找许多错误。 http://valgrind.org/