了解堆上保留内存的大小

3

有没有一种方法可以获取堆上先前分配内存的大小?
例如:

//pseudo-code

void* p = operator new (sizeof(int) * 3);
unsigned size = getSomeHow(p);  

你的意思是之前在你的函数代码中分配的,还是你的线程控制流或进程在堆上总体上分配的? - einpoklum
3个回答

8

并非所有时候都可以这样做,因为operator new()可以以任何合理的方式进行重载,甚至可能不使用运行时堆。

如果在Visual C++中使用malloc()实现operator new(),则可以使用_msize()


5
尽管Sharptooth的答案是正确的(new可以被重载),但解决方案可能就在这个事实中。通过重载new,您可以轻松地添加自己的new和delete实现。在您的new实现中,您应该:
- 编辑:将大小舍入到8字节的下一个倍数 - 在应用程序请求的大小上添加8个字节 - 调用系统内存分配例程(例如,在Windows中使用HeapAlloc) - 在前8个字节中填写最初请求的大小 - 将返回的指针加8并将其返回给应用程序
delete运算符应该执行相反的操作:
- 从应用程序给出的指针中减去8个字节 - 调用系统内存释放例程
如果您以这种方式完成,请确保实现所有类型的new和delete(抛出和非抛出,new和new[],delete和delete[]等)。
还要注意第三方库。它们有时会将对new的调用放在DLL的编译代码中,而将对delete的调用放在头文件中。这意味着new和delete将使用不同的实现,导致应用程序崩溃。
编辑:
需要将大小舍入到8字节的倍数,并添加8个字节,因为数据应存储在其大小的倍数地址处:
- 字符可以存储在任何位置 - 短必须存储在偶数地址上 - 长必须存储在4的倍数地址上 - 双精度浮点数必须存储在8的倍数地址上
由于双精度浮点数是我所知道的最大本地数据类型,因此我们将舍入到8字节的倍数,并添加8个字节以确保满足这些要求。

1
为什么要精确地8个字节而不是“足以存储size_t变量的字节数”? - sharptooth
因为本地数据类型需要存储在其大小的倍数地址上。通常,最大的数据类型是double,它有8个字节。因此,我们需要将大小和指针增加8个字节,以使其成为8个字节的倍数。(对我的帖子进行轻微更正,以确保我们保持这些8个字节的倍数)。 - Patrick
好的,我明白了。那么代码不应该是 max(sizeof(double), sizeof(void*)) 或类似的东西,这样代码才能在1024位(或其他)计算机上移植吗? - sharptooth

1
  • 您可以重写new运算符,调用malloc()并将大小存储在全局的std::map<void*, size> alloc中。

然后,这个getSomeHow()函数将按照您的要求进行操作:

getSomeHow(void *p){
  return alloc[p]; 
}

你也可以编写自己的 malloc() ,并设置加载器使用你的 malloc() 而不是标准的 malloc() 。我已经为了追踪目的这样做了,它可以正常工作。

太好了,但为什么不只是分配一个稍大的块,在其开头写入分配的大小并返回偏移指针呢? - sharptooth
哦,是的,实际上好多了! - Ben
@Ben,你能否提供一些关于如何编写自己的malloc函数的提示吗?这非常吸引我。先谢谢了。 - There is nothing we can do
@我们无能为力:您使用的是哪个操作系统? - Ben
你需要编写一个C文件,其中包含自己的malloc()、realloc()和free()函数(函数声明必须与stdlib.h中的相同)。然后将其编译为动态库(dll),并告诉系统加载你的malloc库。不幸的是,我不知道如何在Windows 7中完成这个最后一步。也许这里有人可以帮忙。 - Ben

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接