确定C中动态分配的内存大小

问题描述 投票:56回答:14

C中是否有办法找出动态分配的内存的大小?

例如,之后

char* p = malloc (100);

是否有办法找出与p相关的内存大小?

c memory dynamic size allocation
14个回答
44
投票

comp.lang.c FAQ list · Question 7.27-

Q。因此,我可以查询malloc程序包以确定分配的块有多大?

A。不幸的是,没有标准或可移植的方法。 (某些编译器提供了非标准扩展。)如果您需要知道,则必须自己对其进行跟踪。 (另请参阅问题7.28。)


1
投票

0
投票

0
投票

0
投票

0
投票

44
投票

没有找到此信息的标准方法。但是,某些实现提供了类似msize的功能来执行此操作。例如:

但是请记住,该malloc将分配所请求的最小大小,因此您应该检查实现的msize变体是否实际返回对象的大小或实际在堆上分配的内存。


11
投票

C的思想是为程序员提供帮助他完成工作的工具,而不是提供改变其工作性质的抽象方法。 C也会尝试避免使事情变得更容易/更安全,如果这样做会牺牲性能限制。

某些您可能想对一个内存区域进行的操作仅需要该区域开始的位置。这些事情包括使用以null终止的字符串,处理区域的前n个字节(如果已知该区域至少这么大),等等。

[基本上,跟踪区域的长度是额外的工作,并且如果C是自动执行的,则有时会不必要地执行它。

许多库函数(例如fread())需要一个指向区域开始的指针以及该区域的大小。如果需要区域的大小,则必须跟踪它。

是的,malloc()实现通常跟踪某个区域的大小,但是它们可以间接执行此操作,或者将其舍入为某个值,或者根本不保留它。即使他们支持它,与您自己跟踪它相比,用这种方法查找大小可能会很慢。

如果您需要一个知道每个区域有多大的数据结构,C可以为您完成。只需使用可跟踪区域大小以及指向该区域的指针的结构即可。


7
投票

否,C运行时库不提供这样的功能。

某些库可能会提供特定于平台或编译器的功能来获取此信息,但通常,跟踪此信息的方法是在另一个整数变量中。


5
投票

这是我看到的创建标记指针以存储大小和地址的最佳方法。所有指针函数仍将按预期工作:

https://stackoverflow.com/a/35326444/638848处偷来的

您还可以为malloc实现包装器,并可以自由添加标签(例如分配的大小和其他元信息)在指针之前由malloc返回。这实际上是C ++编译器的方法使用对虚拟类的引用标记对象。这是一个工作例如:

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

void * my_malloc(size_t s) 
{
  size_t * ret = malloc(sizeof(size_t) + s);
  *ret = s;
  return &ret[1];
}

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

size_t allocated_size(void * ptr) 
{
  return ((size_t*)ptr)[-1];
}

int main(int argc, const char ** argv) {
  int * array = my_malloc(sizeof(int) * 3);
  printf("%u\n", allocated_size(array));
  my_free(array);
  return 0;
}

[此方法相对于具有大小和指针的结构的优势

 struct pointer
 {
   size_t size;
   void *p;
 };

是,您仅需要替换malloc和free调用。所有其他指针操作不需要重构。


3
投票

[就像其他人已经说过的:不,没有。

此外,在这里我总是避免使用所有特定于供应商的功能,因为当您发现确实需要使用它们时,通常表明您做错了。您应该单独存储大小,或者根本不需要知道大小。使用供应商功能是丧失使用C语言编写的主要好处之一的可移植性的最快方法。


2
投票

我希望这取决于实现。如果您获得标头数据结构,则可以将其投射回指针并获得其大小。


2
投票

每个人都告诉你不可能的事情在技术上是正确的(最好的一种正确的选择。)>

出于工程原因,依靠malloc子系统准确地告诉您分配的块的大小是一个坏主意。为了使自己相信这一点,请想象您正在编写一个具有几个不同内存分配器的large

应用程序-也许您一部分使用了原始libc malloc,而另一部分使用了C ++ operator new,然后使用了一些特定的Windows API的另一部分。因此,您到处都有各种各样的void*。编写一个可以在这些void*中的any上运行的函数是不可能的,除非您能以某种方式从指针的值中得知它来自哪个堆。

因此,您可能希望使用某种约定来包装程序中的每个指针,这些约定指示指针来自何处(以及需要将指针返回到何处)。例如,在C ++中,我们将其称为std::unique_ptr<void>(对于需要operator delete'的指针)或std::unique_ptr<void, D>(对于需要通过某种其他机制D返回的指针)。如果愿意,您可以在C中做相同的事情。而且,一旦将指针包装在更大的更安全的对象中[[anyway

中,这只是struct SizedPtr { void *ptr; size_t size; }的一小步,因此您无需再担心分配的大小。

但是。

个很好的理由,为什么您可能合法地想知道分配的实际基础大小。例如,也许您正在为您的应用程序编写一个性能分析工具,该工具将报告每个子系统已使用的实际内存量,而不只是报告程序员正在使用的[内存量。如果每个10字节分配都是在后台秘密使用16字节,那真是太好了! (当然,还有其他开销,您不是用这种方式来衡量的。但是还有其他用于[[that
作业的工具。)或者也许您只是在研究realloc的行为。平台。或者,您可能想“扩大”不断增长的分配的能力,以避免将来premature重新分配。示例:SizedPtr round_up(void *p) { size_t sz = portable_ish_malloced_size(p); void *q = realloc(p, sz); // for sanitizer-cleanliness assert(q != NULL && portable_ish_malloced_size(q) == sz); return (SizedPtr){q, sz}; } bool reserve(VectorOfChar *v, size_t newcap) { if (v->sizedptr.size >= newcap) return true; char *newdata = realloc(v->sizedptr.ptr, newcap); if (newdata == NULL) return false; v->sizedptr = round_up(newdata); return true; } 要获取非空指针后的分配大小已从libc malloc直接返回 –不是来自自定义堆,也没有指向对象的中间–您可以使用以下OS特定的API,为方便起见,我将它们捆绑到“便携式的”包装函数中。如果您发现无法使用此代码的通用系统,请发表评论,我将尝试对其进行修复!
#if defined(__linux__)
// https://linux.die.net/man/3/malloc_usable_size
#include <malloc.h>
size_t portable_ish_malloced_size(const void *p) {
    return malloc_usable_size((void*)p);
}
#elif defined(__APPLE__)
// https://www.unix.com/man-page/osx/3/malloc_size/
#include <malloc/malloc.h>
size_t portable_ish_malloced_size(const void *p) {
    return malloc_size(p);
}
#elif defined(_WIN32)
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/msize
#include <malloc.h>
size_t portable_ish_malloced_size(const void *p) {
    return _msize((void *)p);
}
#else
#error "oops, I don't know this system"
#endif

#include <stdio.h>
#include <stdlib.h>  // for malloc itself

int main() {
    void *p = malloc(42);
    size_t true_length = portable_ish_malloced_size(p);
    printf("%zu\n", true_length);
}

经过测试:

Visual Studio,Win64 — _msize

[GCC / Clang,glibc,Linux — _msize

    Clang,libc,Mac OS X-malloc_usable_size
  • [Clang,jemalloc,Mac OS X –可以在实践中使用,但我不信任它(将jemalloc的malloc_usable_size和本机libc的malloc_size混合在一起]
  • 应该与malloc_size一起正常使用
  • 如果不使用malloc进行编译,则应与malloc_size一起正常工作>
  • 应该与jemalloc on Linux一起正常使用
  • 如果使用malloc,则无法获取大小。另一方面,如果使用OS API动态分配内存,例如Windows dlmalloc on Linux,则可以这样做。

  • 1
    投票

    现在,我知道这并不能回答您的特定问题,但是您可以跳出框框思考……这在我看来,您可能不需要知道。好吧,好吧,不,我不是说您的实现错误或不合常规...我的意思是,您可能(不查看您的代码,我只是在猜测)您可能只是想知道您的数据是否适合如果是这种情况,则此方法可能更好。如果确实是您要处理的,它应该不会提供过多的开销,并且可以解决您的“拟合”问题:

    © www.soinside.com 2019 - 2024. All rights reserved.