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