在C中,对于库来说,允许用户通过使用与malloc()
类似的函数的全局函数指针以及应该与{{1}类似的函数来自定义内存分配是很简单的。 }。例如,SQLite使用这种方法。
C ++使事情变得复杂,因为分配和初始化通常是融合的。从本质上讲,我们希望只为一个库获取被覆盖free()
和operator new
的行为,但实际上没有办法实现这一点(我相当肯定,但不是100%)。
如何在C ++中完成?
Here是第一个用函数operator delete
复制new
表达式的语义的东西。
我不知道这是否有用,但只是为了好玩,here是一个更复杂的版本,也试图复制Lib::make<T>
表达式的语义。
这是一个面向目标的问题,所以我不一定要寻找代码审查。如果有更好的方法可以这样做,只需这样说并忽略链接。
(通过“allocator”我只是指分配内存的东西。我不是指STL分配器概念,甚至不是为容器分配内存。)
为什么这可能是可取的:
Here是来自Mozilla dev的博客文章,他们认为图书馆应该这样做。他给出了几个允许库用户自定义库分配的C库示例。我查看了其中一个示例SQLite的源代码,并看到此功能也在内部用于通过故障注入进行测试。我不是在编写任何需要像SQLite一样防弹的东西,但它似乎仍然是一个明智的想法。如果不出意外,它允许客户端代码弄清楚“哪个库正在占用我的记忆以及什么时候?”。
答案 0 :(得分:5)
简单回答:不要使用C ++。对不起,开玩笑。
但是如果你想对C ++中的内存管理,跨库/模块边界以及完全通用的方式采取这种绝对控制,你可能会遇到一些可怕的悲痛。我建议大多数人寻找不做其他事情的理由。
多年来(实际上几十年)我经历了多次相同基本思想的迭代,尝试将全局级别的运算符new / new [] / delete / delete []天真地重载为基于链接器的特定于平台的解决方案的解决方案,我实际上处于您现在所需的位置:我有一个系统可以让我看到每个插件分配的内存量。但是我并没有通过你想要的那种普遍的方式达到这一点(而且我最初也是如此)。C ++因为分配和初始化而使事情变得复杂 通常是融合的。
我会对这个陈述略微扭曲: C ++使事情变得复杂,因为初始化和分配通常是融合的。我所做的只是在这里交换顺序,但最复杂的部分不是分配想要初始化,而是因为初始化通常想要分配。
采取这个基本的例子:
struct Foo
{
std::vector<Bar> stuff;
};
在这种情况下,我们可以通过自定义内存分配器轻松分配Foo:
void* mem = custom_malloc(sizeof(Foo));
Foo* foo = new(foo_mem) Foo;
...
foo->~Foo();
custom_free(foo);
...当然,我们可以将这一切包括在内,以符合RAII,实现异常安全等。
除了现在问题级联。使用stuff
的{{1}}成员希望使用std::vector
,现在我们还有第二个问题需要解决。我们可以使用我们自己的分配器来使用std::allocator
的模板实例化,如果需要传递给分配器的运行时信息,可以覆盖Foo的构造函数,将该信息与分配器一起传递给向量构造函数。
但是std::vector
呢?它的构造函数也可能想为各种不同的对象分配内存,因此问题级联,级联和级联。
考虑到这个问题的困难,以及我尝试的替代性,一般化的解决方案以及移植时的悲痛,我已经确定了一种完全去泛化的,有些务实的方法。
我解决的解决方案是有效地重新发明整个C和C ++标准库。我知道,这很恶心,但在我的情况下,我有更多的借口。我正在开发的产品实际上是一个引擎和软件开发工具包,旨在允许人们使用任何编译器,C运行时,C ++标准库实现和他们想要的构建设置为其编写插件。为了允许以ABI兼容的方式通过这些中央API传递矢量或集合或映射之类的东西,除了许多C标准函数之外,还需要滚动我们自己的标准兼容容器。
然后,这个devkit的整个实现围绕着这些分配函数:
Bar
...并且整个SDK围绕着这两个,包括内存池和&#34;子分配器&#34;。
对于我们无法控制的第三方图书馆,我们只是SOL。其中一些图书馆有同样雄心勃勃的事情,他们想要对他们的记忆管理,并试图覆盖它只会导致各种冲突,并打开各种各样的蠕虫。当使用像OGL这样想要分配大量系统内存的东西时,也有非常低级别的驱动程序,我们无法做任何事情。
然而,我发现这个解决方案能够很好地回答基本问题:&#34;谁/什么正在占用所有这些记忆?&#34;很快:一个问题通常比与时钟周期相关的类似问题(我们可以启动任何分析器)更难回答。它仅适用于我们控制下的代码,使用此SDK,但我们可以在每个模块的基础上使用此系统获得非常彻底的内存故障。我们还可以设置内存使用的表面上限,以确保实际上正确处理内存不足错误,而不会实际耗尽系统中可用的所有连续页面。
所以在我的情况下,这个问题是通过政策解决的:通过构建统一的编码标准和符合它的中央库,在整个代码库中使用(以及第三方为我们的系统编写插件)。它可能不是您正在寻找的答案,但这最终成为我们尚未找到的最实用的解决方案。