【问题标题】:How can I get the size of a memory block allocated using malloc()? [duplicate]如何获取使用 malloc() 分配的内存块的大小? [复制]
【发布时间】:2010-11-15 13:41:32
【问题描述】:

可能的重复:
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 风格的函数中获得了一个指向一块已分配内存的指针。 现在,出于调试目的了解如何 big 这个指针指向的分配的内存块是。

还有什么比盲目地越界引发异常更优雅的吗?

提前致谢, 安德烈亚斯

编辑:

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

编辑2:

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

编辑3:

嗯。我已经尝试了我上面描述的方式,除了例外,它有效。 至少在我调试并确保在通话后立即 到图书馆出口,我跑过缓冲区边界。像魅力一样工作。

它只是不够优雅,也不能用于生产代码。

【问题讨论】:

  • 那里没有有用的答案。
  • @AndreasT:你能详细说明一下吗?您在寻找什么,但在这些问题中的一个或另一个上没有得到回答(stackoverflow.com/questions/232691/array-size-from-pointer-in-c 似乎与您在此处提出的问题特别接近)。现在,这似乎是重复的 - 如果你能澄清你想要做什么,也许我们可以找到更匹配的答案......
  • 在你提到的网站上,搜索没有向我建议,它是第三个答案,而不是接受的一个,它提供了这个信息:msize() 或类似的函数 (_msize()等等)。我不是在搜索数组的大小,我想知道在给定位置分配了多少字节内存。这当然或多或少是相同的问题,因为特别是在 C 中,您分配数组和大内存块的方式相同。但我不需要知道可能附加了一些大小信息的数组。我需要分配的内存块的大小。
  • C 语言的相似性对我来说并不明显。

标签: c++ c memory-management malloc


【解决方案1】:

这不是标准的,但如果您的库有一个 msize() 函数,它将为您提供大小。

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

【讨论】:

  • +1 我几年前做过。实现起来很简单,非常有用
  • 我无权访问源代码。
  • 但是 _msize 提示可能会出错。谢谢!
  • 检查 _debug_malloc 包。至少在调试版本中可能有一个运行时库来获取 malloc 信息。一般来说,虽然你不应该假设这是可能的设计你的代码
  • 你也可以使用malloc_usable_size()函数,它是在GNU平台上提供的。
【解决方案2】:

如果您不介意为了调试而使用低俗的暴力,您可以使用#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)

等等

【讨论】:

  • 除了对齐问题,这实际上是最好的便携方式。如果你使用像 dlmalloc 这样更冒险的东西,你可以利用弱链接,但对于 PC 应用程序来说,这可能是矫枉过正。
  • 这听起来也不错,但我无权访问代码。
  • 因为我在不知不觉中用几乎相同的解决方案回答了一个重复的问题,所以它一定值得投票!
  • 这并没有像写的那样工作,似乎有一些问题,但我让它工作了。不错的技巧!
  • @ApproachingDarknessFish 你能贴出代码吗?
【解决方案3】:

C 运行时库不提供这样的功能。此外,故意引发异常也不会告诉您该块有多大。

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

您的 C 运行时库可能提供一些可以查询已分配块的堆调试函数(毕竟,free() 需要知道块有多大),但任何此类事情都会不可携带。

【讨论】:

    【解决方案4】:

    使用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

    【讨论】:

    • 真的吗?这怎么可能?一些没有调试信息的 .a 或 .so 文件中的代码会被它覆盖吗?如果是的话:酷! B)
    • 弱引用。链接器将为您覆盖对 malloc 的符号引用并将它们指向您指定的位置。
    • 是的,不需要调试信息,任何库都包含一个符号表,用于它提供的符号以及它需要从其他地方获取的符号。因此,您可以告诉链接器将哪个函数与可执行文件的 malloc 符号绑定。
    【解决方案5】:

    不,当超出其边界时,您不能依赖异常,除非它在您的实现文档中。这是您编写程序时真正不需要知道的东西的一部分。如果您真的想知道,请深入研究编译器的文档或源代码。

    【讨论】:

    • 这被否决的任何特殊原因?
    • 我没有反对,但可能是因为 malloc 和对 malloc 内存的访问不知道抛出异常,是 C 的一部分。
    • 确实如此。我可以请求该内存块,然后引发访问冲突,它就可以正常工作。我在 c++ 中按照标记状态执行此操作,因此会引发异常。
    • 在 Windows 上,您可能会遇到结构化异常(访问冲突),因为这是操作系统传达您已越界的方式。在 Linux 上,我认为等效的是分段错误。您的运行时是否将这些转换为 C++ 异常取决于实现。
    • 这也很可疑。正如您所说,在 Windows 上您可能会遇到访问冲突,而在 Linux 上您可能会遇到分段错误。在实际上不知道的情况下,我怀疑这些是由虚拟内存管理器引起的,因此表示离开内存页面而不是分配的内存区域。
    【解决方案6】:

    没有标准的 C 函数可以做到这一点。根据您的平台,可能存在一种不可移植的方法 - 您使用的是什么操作系统和 C 库?

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

    【讨论】:

      【解决方案7】:

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

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

      【讨论】:

      • 我一定会去看看的。
      【解决方案8】:

      部分解决方案:在 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 会极大地增加应用程序的内存需求。

      【讨论】:

        【解决方案9】:

        做你想做的事的方法是成为分配器。如果您过滤所有请求,然后将它们记录下来以进行调试,那么您可以在内存空闲时找出您想要的内容。

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

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

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

        【讨论】:

        • 分配内存的不是我,是我没有源访问权限的库。
        猜你喜欢
        • 2011-06-24
        • 1970-01-01
        • 2013-01-28
        • 2016-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-26
        • 2022-07-21
        相关资源
        最近更新 更多