如何使用C++;堆管理器跟踪分配对象的大小? 我想在堆中分配对象时,估计C++内存消耗。我可以从sizeof(object)开始计算,并将其四舍五入到堆块的最近倍数(通常为8字节)。但是,如果整个分配的块都被分配给分配的对象,那么当我要求它删除指针时,堆管理器如何告诉对象的大小

如何使用C++;堆管理器跟踪分配对象的大小? 我想在堆中分配对象时,估计C++内存消耗。我可以从sizeof(object)开始计算,并将其四舍五入到堆块的最近倍数(通常为8字节)。但是,如果整个分配的块都被分配给分配的对象,那么当我要求它删除指针时,堆管理器如何告诉对象的大小,c++,gcc,llvm,C++,Gcc,Llvm,如果堆管理器跟踪每个对象的大小,是否意味着我应该在计算中为每个分配的对象添加~4字节到堆管理器内部开销的总内存消耗中?还是以更紧凑的形式存储这些信息?堆内存分配的额外成本(内存方面)是多少 我知道我的问题非常具体于实现,但我很欣赏关于gcc等主要实现的堆元数据存储的任何提示(或者可能是关于libc)。堆分配器不是免费的。每个分配块的成本(包括大小和搜索(如果使用“查找最佳”算法),免费连接块的成本,以及当请求的大小小于返回的块大小时每个块丢失的大小。在内存碎片方面也有成本。考虑在你的堆中间放置一

如果堆管理器跟踪每个对象的大小,是否意味着我应该在计算中为每个分配的对象添加~4字节到堆管理器内部开销的总内存消耗中?还是以更紧凑的形式存储这些信息?堆内存分配的额外成本(内存方面)是多少


我知道我的问题非常具体于实现,但我很欣赏关于gcc等主要实现的堆元数据存储的任何提示(或者可能是关于libc)。

堆分配器不是免费的。每个分配块的成本(包括大小和搜索(如果使用“查找最佳”算法),免费连接块的成本,以及当请求的大小小于返回的块大小时每个块丢失的大小。在内存碎片方面也有成本。考虑在你的堆中间放置一个小的1字节的分配。此时,您不能再返回大于堆的1/2的连续块-堆的一半是碎片。优秀的分配者应对上述所有问题,并努力实现所有利益的最大化

考虑以下分配系统(在许多手持游戏设备上使用了十多年的许多实际应用程序。)

创建一个主堆,其中每个分配都有上一个ptr、下一个ptr、大小以及可能的其他信息。将其四舍五入到每个条目16字节。在返回实际内存指针之前或之后存储此信息-这是您的选择,因为每个都有优点。是的,您正在此处分配请求的大小+16字节

现在只需保留一个指向空闲列表和可能已使用列表的指针

分配是通过在空闲列表中找到一个足够大的块供我们使用,并将其拆分为请求的大小和剩余部分(第一次拟合),或者通过搜索整个列表以获得尽可能精确的匹配(最佳拟合)来完成的。很简单

释放是将当前项移回空闲列表中,如果可能,将彼此相邻的区域连接起来。你可以看到这是如何变成O(n)的

对于较小的分配,获取单个分配(从新创建的堆或全局内存),该分配将作为单元分配区域。将此区域拆分为“块大小”区块地址,并将这些地址推送到空闲堆栈上。分配正在从此列表中弹出一个地址。释放只是将分配推回到列表中—都是O(1)

然后在malloc/new/etc中,检查大小是否在单位大小内,从单位分配器分配,否则使用O(n)分配器。我的研究表明,您可以获得90-95%的分配,以适应单元分配器的块大小,而不会出现太多问题

此外,您还可以为内存池分配内存块,并在反复使用内存池时将其保留为已分配状态。一些较大的分配管理起来要便宜得多(Unix系统使用了很多…)

优点:

  • 所有单元分配都没有外部碎片
  • 小的分配会持续运行
  • 更大的分配可以根据所请求数据的确切大小进行调整
缺点:

  • 如果希望内存小于所需的块,则需要支付内部碎片成本
  • 在您的小数据块大小之外的许多分配和释放最终会使您的内存碎片化。这会导致各种各样的不愉快。这可以在操作系统帮助下进行管理,也可以在alloc/free order上进行管理
  • 一旦你得到1000个大的分配,CPU的价格就会上涨。板/多个堆也可用于修复此问题

有很多很多方案,但这一方案很简单,已经在商业应用程序中使用了很长时间,所以我想从这里开始。

非常相关:可能相关:@Justin:故事的一半。还有
deletebaseptr
,它可以调用
Derived::~Derived
。在这种情况下,
::运算符delete
将需要
sizeof(派生)
,而不是
sizeof(基本)
@Justin那么,在实际生产实现中,堆管理器的开销应该是每个对象+4-8字节吗?这是小物件所需数量的两倍!为什么没有优化?@FyodorMenshikov可以进行优化,例如,通过对不同的对象大小使用不同的堆。因此,在小于256字节的对象堆中,大小信息只需要1字节。但是如果你没有很多小对象的动态分配,它可能不值得增加复杂性。我理解你的观点,在某些情况下手动内存管理有它的好处。我在gamedev工作时用过一个。但我在这个问题上的主要关注点是“开箱即用”的PC(=足够的资源)堆管理器特性。对它有什么期待?看看glibc-malloc代码。看看其他分配器。他们都使用相同的技巧。有些人依靠操作系统为他们提供足够大的虚拟内存块,并让操作系统处理碎片和物理映射。而且
PC=足够的资源
我不得不承认,这让我咯咯地笑了,尽管我理解你的意思。