概要
本文比较各种内存分配器(Allocator)在用于STL容器上的性能。参与本次比较的Allocator有:
- 普通new/delete (用作性能基准)
- AutoFreeAlloc
- ScopeAlloc
选择的STL容器为map。其他容器如std::list, std::set, std::multi_set, std::multi_map类似1。
对比程序
测试方法 - 对比以下四种情况:
- 使用标准的std::map<int, int>。
- 使用ScopeAlloc作为分配器。即std::Map<int, int>。
- 使用AutoFreeAlloc作为分配器。即std::Map<int, int, std::less<int>, std::AutoFreeAlloc>。
- 使用ScopeAlloc作为分配器,且共享同一个std::BlockPool。
测试程序(参见<stdext/Map.h>):
template <class LogT> class TestMap : public TestCase { WINX_TEST_SUITE(TestMap); WINX_TEST(testCompare); WINX_TEST_SUITE_END(); public: enum { N = 20000 }; void doStlMap(LogT& log) { typedef std::map<int, int> MapT; log.print("===== std::map =====\n"); std::PerformanceCounter counter; { MapT coll; for (int i = 0; i < N; ++i) coll.insert(MapT::value_type(i, i)); } counter.trace(log); } void doMap1(LogT& log) { typedef std::Map<int, int, std::less<int>, std::AutoFreeAlloc> MapT; log.print("===== std::Map (AutoFreeAlloc) =====\n"); std::PerformanceCounter counter; { std::AutoFreeAlloc alloc; MapT coll(alloc); for (int i = 0; i < N; ++i) coll.insert(MapT::value_type(i, i)); } counter.trace(log); } void doMap2(LogT& log) { typedef std::Map<int, int> MapT; log.print("===== std::Map (ScopeAlloc) =====\n"); std::PerformanceCounter counter; { std::BlockPool recycle; std::ScopeAlloc alloc(recycle); MapT coll(alloc); for (int i = 0; i < N; ++i) coll.insert(MapT::value_type(i, i)); } counter.trace(log); } void doShareAllocMap(LogT& log) { typedef std::Map<int, int> MapT; std::BlockPool recycle; log.newline(); for (int i = 0; i < 5; ++i) { log.print("===== doShareAllocMap =====\n"); std::PerformanceCounter counter; { std::ScopeAlloc alloc(recycle); MapT coll(alloc); for (int i = 0; i < N; ++i) coll.insert(MapT::value_type(i, i)); } counter.trace(log); } } void testCompare(LogT& log) { for (int i = 0; i < 5; ++i) { log.newline(); doStlMap(log); doMap2(log); doMap1(log); } doShareAllocMap(log); } };
测试结果
===== std::map =====
---> Elapse 29649998 ticks (8283.18 ms) (0.14 min) ...
===== std::Map (ScopeAlloc) =====
---> Elapse 9045729 ticks (2527.06 ms) (0.04 min) ...
===== std::Map (AutoFreeAlloc) =====
---> Elapse 9683232 ticks (2705.16 ms) (0.05 min) ...
===== std::map =====
---> Elapse 38099194 ticks (10643.59 ms) (0.18 min) ...
===== std::Map (ScopeAlloc) =====
---> Elapse 15013312 ticks (4194.20 ms) (0.07 min) ...
===== std::Map (AutoFreeAlloc) =====
---> Elapse 15039592 ticks (4201.54 ms) (0.07 min) ...
===== std::map =====
---> Elapse 24698608 ticks (6899.93 ms) (0.11 min) ...
===== std::Map (ScopeAlloc) =====
---> Elapse 10867094 ticks (3035.89 ms) (0.05 min) ...
===== std::Map (AutoFreeAlloc) =====
---> Elapse 15611309 ticks (4361.26 ms) (0.07 min) ...
===== std::map =====
---> Elapse 37594376 ticks (10502.56 ms) (0.18 min) ...
===== std::Map (ScopeAlloc) =====
---> Elapse 8846240 ticks (2471.33 ms) (0.04 min) ...
===== std::Map (AutoFreeAlloc) =====
---> Elapse 8667671 ticks (2421.44 ms) (0.04 min) ...
===== std::map =====
---> Elapse 30175306 ticks (8429.93 ms) (0.14 min) ...
===== std::Map (ScopeAlloc) =====
---> Elapse 9033720 ticks (2523.71 ms) (0.04 min) ...
===== std::Map (AutoFreeAlloc) =====
---> Elapse 8723023 ticks (2436.91 ms) (0.04 min) ...
===== doShareAllocMap =====
---> Elapse 8441194 ticks (2358.18 ms) (0.04 min) ...
===== doShareAllocMap =====
---> Elapse 7651772 ticks (2137.64 ms) (0.04 min) ...
===== doShareAllocMap =====
---> Elapse 7900730 ticks (2207.19 ms) (0.04 min) ...
===== doShareAllocMap =====
---> Elapse 7861035 ticks (2196.10 ms) (0.04 min) ...
===== doShareAllocMap =====
---> Elapse 7530844 ticks (2103.86 ms) (0.04 min) ...
测试结论
使用ScopeAlloc或者AutoFreeAlloc后,STL容器的性能有显著提高。而ScopeAlloc与AutoFreeAlloc在该容器存在大量内存分配时区别不显著2。另外,由于内存池技术的作用,ScopeAlloc在Share同一个BlockPool后,性能略有改善。