【问题标题】:Find if allocation is trivially resizable?查找分配是否可以轻松调整大小?
【发布时间】:2021-12-31 22:59:02
【问题描述】:

realloc 可能只是在这里和那里更新簿记信息以增加您的分配大小,或者实际上可能malloc 一个新的和memcpy 以前的分配(或可能失败)。

我希望能够查询内存管理器,如果分配是可调整大小的(可能是因为它保留的比我mallocd 多,或者因为它能够合并相邻的块,等等。 .) 如果是,那么我会要求它继续这样做,否则我想自己以任意顺序将原始分配的任意子集 mallocmemcpy

其他 StackOverflow 答案似乎是这四个之一:

  • 无论如何建议realloc。对于大量数据,这可能效率很低,在这种情况下,双重复制可能会产生严重影响。通常,这是最快的便携路线。
  • 建议手动malloc + memcpy + free。这更糟,因为现在不是 some 在分配可能无法调整大小时进行双重复制,而是在每次分配填满时 everything 被双重复制。表现非常糟糕。
  • 建议一个特定于平台的扩展。这是不切实际的,因为我的代码和很多 C 代码一样,需要可移植性。
  • 暗示这是不可能的。 C 已经假设存在一个内存管理器,它能够在适当的位置调整分配的大小创建一个新的。那么,为什么我不能对它进行更高级别的控制呢?我们可以对齐malloc;为什么不是这个?

注意:这个问题同时发布在 C 和 C++ 标记下,因为任何一种语言的解决方案都是可接受且相关的。

编辑 1:

用FB向量的话来说:

但是等等,还有更多。许多内存分配器不支持就地重新分配,尽管大多数都可以。这来自现在臭名昭著的 realloc() 设计,以不透明地执行就地重新分配或 allocate-memcpy-deallocate 循环。这种缺乏控制随后迫使所有基于 clib 的分配器设计避免就地重新分配,其中包括 C++ 的 new 和 std::allocator。这是效率的重大损失,因为非常便宜的就地重新分配可能意味着不那么激进的增长战略。反过来,这意味着更少的闲置内存和更快的重新分配。

this

【问题讨论】:

  • 没有标准或可移植的方式来做到这一点。在这种情况下,这可能就是“不可能”所指的。并不是说它在技术上是不可能实现的。只是 C 规范没有指定,因此没有非标准扩展是不可能的。
  • @kaylum WG14 是否愿意接受这样的建议?还是 libc 不是他们当前的重点?
  • 您的列表似乎正确且详尽。你的问题到底是什么?
  • 如果您需要自定义语义,建议您编写自己的分配器。你分配了多少内存?我无法想象像大块内存的副本要花那么长时间。我看到quora.com/… 在我的电脑上复制 1GB 需要 0.15 秒,这不算多,你不会经常重新分配。
  • 对于非平凡的可重新分配情况,您为什么更愿意手动使用mallocmemcpy?为什么不让realloc 为你做呢? “双重复制”是什么意思?应该只执行一份副本。此外,虽然复制可能既昂贵又糟糕,但大多数人并不在意,因为它通常会通过以指数方式增长缓冲区来分期偿付。

标签: c++ c memory-management realloc


【解决方案1】:

我想你想要得到的是你的 malloc'ed 内存块之后的空闲空间大小。有可能,内存管理器在每个块之前都预留了一个头,你可以从块头中得到你想要的信息,但显然由于各种内存管理器的实现不同,它是不可移植的。 我觉得更好的办法是自己使用内存池来管理堆内存,这样会更加高效和便携。

【讨论】:

  • 不,块的可抗性取决于各种因素,我只想知道块是否可以在运行时调整到某个大小。这可以便携地完成,因为做一些奇怪的事情的实现可以合法地void *resize(void *p) { return NULL; }
【解决方案2】:

标准内存接口有据可查。如果您想要一些不属于该界面的功能,您的解决方案将是自定义的、第三方的或特定于平台的。

  • 暗示这是不可能的。 C 已经假定存在一个内存管理器,它能够调整分配的大小或创建一个新的分配。那么,为什么我不能对其进行更高级别的控制呢?

因为它不是标准接口的一部分。它可以成为标准接口的一部分这一事实并不意味着它标准接口的一部分。

...我们可以对齐malloc;为什么不是这个?

如果您希望它成为标准,请向工作组提出更改建议。它不会很快到达。

如果您想让某些东西现在工作,您需要编写自己的分配器或找到满足您要求的第三方分配器。

注意

  • 建议一个特定于平台的扩展。这是不切实际的,因为我的代码和很多 C 代码一样,需要可移植性。

不是一个真正的问题(或者至少,人们经常可以很好地应对)。您可能必须为要支持的每个平台编写不同的实现(并在没有更好的地方使用 realloc),但这对于跨平台代码并不少见。

【讨论】:

  • "如果您希望它成为标准,请向工作组提出更改"。 C 委员会对这种 libc 的添加有多大的接受度? AFAIK 对 libc 的唯一更改是格式说明符、原子和线程(使用 C++)、新宏和一些边界检查函数。大多数更改都是可选的,但确认它们不存在的功能测试宏除外。
  • 我可能不会尝试,直到我编写了一个我很高兴与库的其余部分保持一致的接口,编写了一个与其他类似提议一致的提议,并测试了一个示例实现glibc 或类似的。不过,您可以先联系当地参与的国家机构。 Contacts
  • 看来我的国家没有参与。不过感谢您的帮助。
【解决方案3】:

无论如何建议重新分配。对于大量数据,这可能是非常低效的,其中双重复制可能会产生严重影响。

由于为什么 realloc 有时可以避免复制和分配的原因,这是一个无关紧要的点,因为在实际实现中,大量数据不存在这种情况。如果您知道分配很大,那么假设 realloc 必须复制和分配是相当安全的。因此,您无需进行“不可能”检查即可做出选择。

如果重新分配是可选的并且您负担不起副本,则无条件选择不重新分配的选项。如果重新分配不是可选的,那么 realloc 是否会复制和分配不会影响您必须执行的操作。

建议一个特定于平台的扩展。这不切实际,因为我的代码和很多 C 代码一样,需要可移植性。

这是实现您所要求的唯一方法,因为没有标准方法来查询 realloc 是否会复制和分配。

但是,请记住,可以通过使用预定义的宏有条件地禁用此功能来移植此类代码。

暗示这是不可能的。

如果您选择依赖标准 C++,这是正确的。

有没有我在搜索中没有遇到的方法?

不,列表是详尽的。

【讨论】:

  • 我接受了这个建议并简单地使用了realloc,因为我不能#ifdef 离开每个平台,也不会制作我自己的分配器/需要一个作为依赖项。
猜你喜欢
  • 1970-01-01
  • 2014-07-03
  • 1970-01-01
  • 1970-01-01
  • 2010-10-11
  • 1970-01-01
  • 1970-01-01
  • 2018-09-14
  • 1970-01-01
相关资源
最近更新 更多