为什么我们需要使用 folly::fbvector 而不是 std::vector 和最初保留大的未提交区域的分配器?
Why do we need to use folly::fbvector instead of std::vector with allocator which reserve large uncommited area initially?
众所周知,如果我们push_back个元素到std::vector<>
,并且如果向量中分配的整个内存都被占用,那么std::vector<>
保留当前内存大小的2倍(分配 2 倍大小的新内存),调整向量大小并将旧数据复制到新内存。
我们可以优化它,Facebook 在 folly-library 中做到了这一点(FBVector 是 Facebook drop-in 对 std::vector 的实现。它针对可重定位类型和 jemalloc https://github.com/facebook/folly/blob/master/folly/FBVector.h#L21).
即当 vector<>
没有足够的内存来 push_back 新元素时,我们分配更多的内存但不是 2 倍(不同的次数:1.3 - 1.5 倍)
说明:https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md
The graphical solver below reveals that choosing k = 1.5 (blue line)
allows memory reuse after 4 reallocations, choosing k = 1.45 (red
line) allows memory reuse after 3 reallocations, and choosing k = 1.3
(black line) allows reuse after only 2 reallocations.
但是为什么我们需要使用 folly::fbvector<>
而不是 std::vector<>
和我们使用 VirtualAllocEx()
(as shown here: For what do I need to use VirtualAlloc/VirtualAllocEx? ), or the same in linux 的自定义分配器,其中:
std::vector<>::reserve()
- 初始保留虚拟地址的大un-commited区域(分配WMA,但不分配PT中的任何PTE),例如初始分配16 GB的虚拟区域并且每次缺少内存来提交内存(分配 PTE - 分配物理区域)等于 1 x SIZE of vector
std::vector<>::resize()
- 然后只提交一批新的页面,在 PT 中只分配新的 PTE,没有 re-allocation 已经使用的内存,也没有将数据从旧内存复制到新
总体:
与 folly::vector<>
相比,这种具有大 un-commited 区域的方法的优点:我们总是只分配新的内存部分,从不复制旧数据。
folly::vector<>
方法相对于 std::vector<>
的优点:有时我们不需要分配新内存,而是将旧数据复制到新数据中记忆应该永远。
这是特定于实现的。 GCC 库确实分配了两倍的空间,但 Visual C++ 却没有。我相信,它也使用 1.5,但不确定。
我相信,folly
应该与操作系统无关,您的方法是 Windows/Linux-specific。
如果您仔细选择类型,对象从旧向量移动到新向量应该不会那么糟糕 - 也就是说,使用 std::unique_ptr
作为数据类型。
众所周知,如果我们push_back个元素到std::vector<>
,并且如果向量中分配的整个内存都被占用,那么std::vector<>
保留当前内存大小的2倍(分配 2 倍大小的新内存),调整向量大小并将旧数据复制到新内存。
我们可以优化它,Facebook 在 folly-library 中做到了这一点(FBVector 是 Facebook drop-in 对 std::vector 的实现。它针对可重定位类型和 jemalloc https://github.com/facebook/folly/blob/master/folly/FBVector.h#L21).
即当 vector<>
没有足够的内存来 push_back 新元素时,我们分配更多的内存但不是 2 倍(不同的次数:1.3 - 1.5 倍)
说明:https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md
The graphical solver below reveals that choosing k = 1.5 (blue line) allows memory reuse after 4 reallocations, choosing k = 1.45 (red line) allows memory reuse after 3 reallocations, and choosing k = 1.3 (black line) allows reuse after only 2 reallocations.
但是为什么我们需要使用 folly::fbvector<>
而不是 std::vector<>
和我们使用 VirtualAllocEx()
(as shown here: For what do I need to use VirtualAlloc/VirtualAllocEx? ), or the same in linux 的自定义分配器,其中:
std::vector<>::reserve()
- 初始保留虚拟地址的大un-commited区域(分配WMA,但不分配PT中的任何PTE),例如初始分配16 GB的虚拟区域并且每次缺少内存来提交内存(分配 PTE - 分配物理区域)等于 1 x SIZE of vectorstd::vector<>::resize()
- 然后只提交一批新的页面,在 PT 中只分配新的 PTE,没有 re-allocation 已经使用的内存,也没有将数据从旧内存复制到新
总体:
与 folly::vector<>
相比,这种具有大 un-commited 区域的方法的优点:我们总是只分配新的内存部分,从不复制旧数据。
folly::vector<>
方法相对于 std::vector<>
的优点:有时我们不需要分配新内存,而是将旧数据复制到新数据中记忆应该永远。
这是特定于实现的。 GCC 库确实分配了两倍的空间,但 Visual C++ 却没有。我相信,它也使用 1.5,但不确定。
我相信,folly
应该与操作系统无关,您的方法是 Windows/Linux-specific。
如果您仔细选择类型,对象从旧向量移动到新向量应该不会那么糟糕 - 也就是说,使用 std::unique_ptr
作为数据类型。