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

时间:2009-08-15 11:21:09

标签: c memory dynamic size allocation

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

例如,在

之后
char* p = malloc (100);

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

15 个答案:

答案 0 :(得分:42)

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

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

答案 1 :(得分:41)

comp.lang.c FAQ list · Question 7.27 -

Q值。那么我可以查询malloc包以找出分配的块有多大吗?

一个。不幸的是,没有标准或便携的方式。 (有些编译器提供非标准扩展。)如果你需要知道,你必须自己跟踪它。 (另见问题7.28。)

答案 2 :(得分:10)

C心态是为程序员提供工具来帮助他完成工作,而不是提供改变工作性质的抽象。如果以牺牲性能限制为代价,C还会尽量避免使事情变得更容易/更安全。

您可能想要对内存区域执行的某些操作仅需要区域开头的位置。这样的事情包括使用以null结尾的字符串,操作区域的第一个 n 字节(如果已知该区域至少这么大),等等。

基本上,跟踪区域的长度是额外的工作,如果C自动完成,它有时会不必要地进行。

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

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

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

答案 3 :(得分:7)

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

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

答案 4 :(得分:4)

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

被盗: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和免费通话。所有   其他指针操作不需要重构。

答案 5 :(得分:3)

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

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

答案 6 :(得分:2)

我希望这是依赖于实现的 如果你有标题数据结构,你可以将它强制转换为指针并获得大小。

答案 7 :(得分:1)

如果使用malloc,则无法获得尺寸。

另一方面,如果您使用OS API动态分配内存,例如Windows heap functions,那么就可以这样做。

答案 8 :(得分:1)

此代码可能适用于大多数Windows安装:

template <class T>
int get_allocated_bytes(T* ptr)
{
 return *((int*)ptr-4);
}

template <class T>
int get_allocated_elements(T* ptr)
{
 return get_allocated_bytes(ptr)/sizeof(T);
}

答案 9 :(得分:1)

这可能有用,代码中的一个小更新:

void* inc = (void*) (++p)
size=p-inc;

但这会导致1,即与p相关联的内存char*。如果是int*,那么结果将是4。

无法找到总分配。

答案 10 :(得分:1)

嗯现在我知道这不是回答你的具体问题,不过在盒子外面思考......它发生在我身上你可能不需要知道。好吧,好吧,不,我不是说你有一个坏的或非正统的实现...我的意思是你可能(没有看你的代码,我只是猜测)你可能只想知道你的数据可以适应分配的内存,如果是这种情况,那么这个解决方案可能会更好。它不应该提供太多的开销,并将解决你的&#34;拟合&#34;问题,如果这确实是你正在处理的事情:

if ( p != (tmp = realloc(p, required_size)) ) p = tmp;

或者如果您需要维护旧内容:

if ( p != (tmp = realloc(p, required_size)) ) memcpy(tmp, p = tmp, required_size);

当然你可以使用:

p = realloc(p, required_size);

并完成它。

答案 11 :(得分:0)

每个人都告诉你这是不可能的在技术上是正确的(最好的正确)。

出于工程原因,依靠malloc子系统准确地告诉您已分配块的大小是一个坏主意。为了说服自己,想象一下你正在编写一个带有几个不同内存分配器的大型应用程序 - 也许你在一个部分中使用原始libc malloc,但是在C ++ operator new中另一部分,然后是另一部分中的一些特定Windows API。所以你有各种各样的void*飞来飞去。编写一个可以在这些void*任何上工作的函数是不可能的,除非你能以某种方式告诉指针的值它来自哪个堆。

因此,您可能希望使用指示指针来自何处的约定(以及需要返回的位置)来包装程序中的每个指针。例如,在C ++中,我们称之为std::unique_ptr<void>(对于需要operator delete'd)或std::unique_ptr<void, D>的指针(对于需要通过其他机制返回的指针D })。如果你愿意,你可以在C中做同样的事情。一旦你将指针包装在更大的更安全的对象 中,它只是struct SizedPtr { void *ptr; size_t size; }的一小步,然后你再也不用担心分配的大小。

<强>然而

有充分理由说明为什么您可能合法地想知道分配的实际基础大小。例如,您可能正在为您的应用编写一个分析工具,该工具将报告每个子系统使用的实际内存量,而不仅仅是程序员认为的内存量他正在使用。如果你的每个10字节分配秘密使用16个字节,那就太知道了! (当然还会有其他开销,你没有用这种方式测量。但是 工作还有其他工具。)或许你只是在研究{{的行为1}}在你的平台上。或者,您可能希望“整理”不断增长的分配容量,以避免将来过早重新分配。例如:

realloc

要获得直接从libc malloc 返回的非空指针后面的分配大小 - 而不是从自定义堆返回,而不是指向对象的中间 - 你可以使用以下特定于操作系统的API,为方便起见,我将其捆绑到“portable-ish”包装函数中。如果您发现此代码不起作用的常见系统,请发表评论,我会尝试修复它!

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;
}

经过测试:

  • Visual Studio,Win64 - _msize
  • GCC / Clang,glibc,Linux - malloc_usable_size
  • Clang,libc,Mac OS X - malloc_size
  • Clang,jemalloc,Mac OS X - 在实践中有效,但我不相信它(默默混合jemalloc的#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); } 和本地libc的malloc
  • 使用jemalloc on Linux
  • 可以正常工作
  • 如果使用malloc_size
  • 进行编译,则应与dlmalloc on Linux一起使用
  • 使用tcmalloc everywhere
  • 可以正常工作

答案 12 :(得分:0)

Quuxplusone写道:“编写一个可以在任何这些void *上工作的函数都是不可能的,除非您能以某种方式从指针的值中得知它来自哪个堆。 Determine size of dynamically allocated memory in C

实际上,在Windows中,_msize通过指针的值为您分配分配的内存大小。如果该地址没有分配的内存,则会引发错误。

int main()
{
    char* ptr1 = NULL, * ptr2 = NULL;
    size_t bsz;    
    ptr1 = (char*)malloc(10);
    ptr2 = ptr1;
    bsz = _msize(ptr2);
    ptr1++;
    //bsz = _msize(ptr1);   /* error */
    free(ptr2);

    return 0;
}

感谢#define集合。这是宏版本。

#define MALLOC(bsz) malloc(bsz)
#define FREE(ptr) do { free(ptr); ptr = NULL; } while(0)
#ifdef __linux__
#include <malloc.h>
#define MSIZE(ptr) malloc_usable_size((void*)ptr)
#elif defined __APPLE__
#include <malloc/malloc.h>
#define MSIZE(ptr) malloc_size(const void *ptr)
#elif defined _WIN32
#include <malloc.h>
#define MSIZE(ptr) _msize(ptr)
#else
#error "unknown system"
#endif

答案 13 :(得分:0)

最近,我在可视化可写入的内存方面苦苦挣扎(即在malloc之后立即使用strcatstrcpy类型的函数)。

这并不是一个非常技术性的答案,但是它可以在调试时为您提供帮助,就像对我有帮助一样。

您可以使用mallocmemset的大小,为第二个参数设置一个任意值(以便您可以识别它),并使用从{{1}获得的指针}。

像这样:

malloc

然后您可以在调试器中可视化分配的内存的外观: enter image description here

答案 14 :(得分:0)

注意:使用_msize仅适用于分配有callocmalloc等的内存。如Microsoft文档所述

_msize函数返回内存块的大小(以字节为单位) 通过调用callocmallocrealloc分配。

否则将引发异常。

https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/msize?view=vs-2019