对于长时间运行的程序,STL 内存管理是否"reliable"?
Is STL memory management "reliable" for a long running program?
我在 C++11 STL 中阅读了很多关于内存管理的 SO 帖子,但我真的找不到令人满意的答案。
我的情况:我开发了一个长时间运行的服务器[它运行了大约4-6周]。目前,我使用了很多旧的C 代码char [x][y]
或位于堆栈上的char [z]
变量。
我怀疑STL 内存管理是否仍然可靠,在一个运行数周并在超过 1000 万个线程的时间内提供服务的程序中广泛使用它,每个线程都会有很多 STL 操作。
更具体地说:我想将位于堆栈上的所有固定大小的变量重写为std::vector<std::string>
或std::string
类型。
我的问题:
- 我可以完全安全地将我的程序重写为新的现代 STL 符号并摆脱旧的 C 代码吗?
- 在数百万个线程中运行这么长时间时是否存在任何内存碎片?
- 性能如何?使用在堆栈上具有变量的旧 C 代码不会对性能产生任何影响。
编译器gcc 4.9.3
我可以完全安全地将我的程序重写为新的现代 STL 符号并摆脱旧的 C 代码吗?
首先,STL并不新鲜;它可以追溯到C++本身标准化之前。其次,我们称之为C++标准库。
第三,只要你的线程遵循C++的要求(即:不要以C++不允许的方式终止),并且你不泄漏内存,那么是的,你会没事的。
在数百万个线程中运行这么长时间时是否存在任何内存碎片?
您正在从存在于堆栈上的对象转向动态分配内存。当然,存在内存碎片的可能性。
这与C++标准库容器完全无关。这是使用动态分配的产物。
同样重要的是,如果您想使用更好的固定大小的堆栈数组,则可以使用std::array<char, ...>
。再说一次,std::string
具有小字符串优化的实现在很多情况下提供了一个很好的折衷方案,如果字符串低于某个最大大小,则放弃分配内存。
性能如何?使用在堆栈上具有变量的旧 C 代码不会对性能产生任何影响。
它使您的堆栈更长,考虑到 1000 万个线程,可能会导致您提交更多内存页。话又说回来,也许不是。
在任何情况下,当涉及到超线程应用程序时,内存分配始终是一个问题。就其性质而言,内存分配必须是可重入的。这意味着互斥锁等。
您可以设计分配和解分配内存的原子方法,但这往往需要分配固定大小。这样的事情往往有其自身的缺点。您可以有从中分配的线程本地内存池。所有这些都需要使用您自己的内存分配器。
但最重要的是...这些问题同样与专门使用C++标准库类型无关。这就是从静态内存到动态分配时发生的情况。无论您使用的是malloc/free
库容器还是标准库容器,问题都出在动态分配上。
首先,我非常感谢所有的评论和Nicol的回答。他关于碎片的最后一条评论一针见血。
1)碎片化取决于这些细节的细节 数以百万计的线程正在做。
在深入分析了该项目之后,我意识到有数百万个内存分配和释放。
因此,我编写了自己的 STL 内存分配器,它:
- 具有维护所有指针的内部
unordered_map
。 - 是多线程安全的。
- 根据第 1 点,它重用标记为自由的释放指针。
- 要卸载控制器,请求的内存大小 [通过 STL] 与 16 字节大小对齐。
我的 STL 内存分配器记录所有请求,这是摘要 [摘要]:
Statistics:
Total allocated Memory: 813'041'344 bytes
Administrative Memory : 3'464'152 bytes
Available pointers : 2'500
+-------------------------------------------------------------------------+
| Index | Aligned Memory Size | Max Used Pointers | Total Requested Count |
+-------------------------------------------------------------------------+
| 1| 48| 296| 49'545'399|
| 2| 64| 469| 73'226'993|
| 3| 80| 1'167| 67'108'769|
| 4| 96| 129| 12'864'168|
| 5| 112| 281| 4'528'422|
| 6| 128| 64| 8'715'454|
| 7| 144| 74| 5'148'202|
| 10| 192| 387| 1'313'920|
| 11| 208| 26| 1'311'779|
| 13| 272| 56| 11'574'551|
| 15| 352| 368| 1'178'994|
| 18| 512| 262| 3'224'044|
| 22| 656| 5| 2'586'081|
+-------------------------------------------------------------------------+
传说:
Aligned Memory Size
:每个请求的块对齐 16 字节 + 32 字节的维护数据。 E.q. 分配 1 个字节会产生一个实际大小为 48 字节的内存块。Max Used Pointers
:这是所有正在运行的线程同时使用此大小的内存块的数量。换句话说,这个内存[Size * Max Used Pointers
]是从操作系统物理上分配的。Total Requested Count
:每次请求分配 [对齐大小] 时,此计数都会增加。
对我来说,这意味着我可以保存数百万个分配和释放,我不知道使用默认 STL 分配器会是什么样子。
2)我可以摆脱旧的C样式代码,我可以使用更多 方便的 STL 容器。
3)性能还可以。对我来说,这意味着我的分配器不是 最快的一个,但考虑到它是完全多线程安全的,并且 每秒服务数千个请求,完全足以满足我的要求 需要。
所以,答案是,[公平地说]我仍然不知道默认的 STL 内存分配器有多可靠,但由于上述事实,我至少得到了
内部发生的事情的线索。假设我的分配器没有错误[在运行很长时间并为数百万个请求提供服务后我可以期待]我可以为我关闭此案例。
- 当vector是tje全局变量时,c++中vector的内存管理
- 当分配一个字符串值并稍后通过分配另一个值进行更改时C++如何管理内存?
- 我有一个线程 1:EXC_BAD_ACCESS(代码 = 1,地址 = 0x8)错误.我认为这是由于内存管理不好.我可以
- 可以通过非原始指针来增强容器矢量管理内存
- 如何使用 std::vector<std::tuple<A,B>> 来管理内存(调整大小、保留,...),但实际上将 As 保留在 B 之前,连续
- 线程管理内存泄漏
- 通过读取文件创建映射<字符串,矢量>时如何管理内存<string>
- 管理内存C++
- ptr_vector如何管理内存
- 在C++Builder/Firemonkey中使用表单创建来管理内存
- 如何正确管理内存(运行时)C++
- 在Node.js中使用Native Abstractions时,如何管理内存
- ostream是如何管理内存的
- C++中管理内存泄漏的问题
- OpenCL:在 CPU 上而不是在 GPU 上更正结果:如何正确管理内存
- deque是如何管理内存的
- 用c++/cli互操作管理内存
- 如何衡量管理内存所花费的时间
- (加速C++)章节管理内存
- 如何在此场景中管理内存