test_pool_alloc.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /* Copyright (C) 2000, 2001 Stephen Cleary
  2. * Copyright (C) 2011 Kwan Ting Chan
  3. *
  4. * Use, modification and distribution is subject to the
  5. * Boost Software License, Version 1.0. (See accompanying
  6. * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  7. */
  8. #include "random_shuffle.hpp"
  9. #include <boost/pool/pool_alloc.hpp>
  10. #include <boost/pool/object_pool.hpp>
  11. #include <boost/detail/lightweight_test.hpp>
  12. #include <algorithm>
  13. #include <deque>
  14. #include <list>
  15. #include <set>
  16. #include <stdexcept>
  17. #include <vector>
  18. #include <cstdlib>
  19. #include <ctime>
  20. // Each "tester" object below checks into and out of the "cdtor_checker",
  21. // which will check for any problems related to the construction/destruction of
  22. // "tester" objects.
  23. class cdtor_checker
  24. {
  25. private:
  26. // Each constructed object registers its "this" pointer into "objs"
  27. std::set<void*> objs;
  28. public:
  29. // True iff all objects that have checked in have checked out
  30. bool ok() const { return objs.empty(); }
  31. ~cdtor_checker()
  32. {
  33. BOOST_TEST(ok());
  34. }
  35. void check_in(void * const This)
  36. {
  37. BOOST_TEST(objs.find(This) == objs.end());
  38. objs.insert(This);
  39. }
  40. void check_out(void * const This)
  41. {
  42. BOOST_TEST(objs.find(This) != objs.end());
  43. objs.erase(This);
  44. }
  45. };
  46. static cdtor_checker mem;
  47. struct tester
  48. {
  49. tester(bool throw_except = false)
  50. {
  51. if(throw_except)
  52. {
  53. throw std::logic_error("Deliberate constructor exception");
  54. }
  55. mem.check_in(this);
  56. }
  57. tester(const tester &)
  58. {
  59. mem.check_in(this);
  60. }
  61. ~tester()
  62. {
  63. mem.check_out(this);
  64. }
  65. };
  66. // This is a wrapper around a UserAllocator. It just registers alloc/dealloc
  67. // to/from the system memory. It's used to make sure pool's are allocating
  68. // and deallocating system memory properly.
  69. // Do NOT use this class with static or singleton pools.
  70. template <typename UserAllocator>
  71. struct TrackAlloc
  72. {
  73. typedef typename UserAllocator::size_type size_type;
  74. typedef typename UserAllocator::difference_type difference_type;
  75. static std::set<char *> allocated_blocks;
  76. static char * malloc(const size_type bytes)
  77. {
  78. char * const ret = UserAllocator::malloc(bytes);
  79. allocated_blocks.insert(ret);
  80. return ret;
  81. }
  82. static void free(char * const block)
  83. {
  84. BOOST_TEST(allocated_blocks.find(block) != allocated_blocks.end());
  85. allocated_blocks.erase(block);
  86. UserAllocator::free(block);
  87. }
  88. static bool ok()
  89. {
  90. return allocated_blocks.empty();
  91. }
  92. };
  93. template <typename UserAllocator>
  94. std::set<char *> TrackAlloc<UserAllocator>::allocated_blocks;
  95. typedef TrackAlloc<boost::default_user_allocator_new_delete> track_alloc;
  96. void test()
  97. {
  98. {
  99. // Do nothing pool
  100. boost::object_pool<tester> pool;
  101. }
  102. {
  103. // Construct several tester objects. Don't delete them (i.e.,
  104. // test pool's garbage collection).
  105. boost::object_pool<tester> pool;
  106. for(int i=0; i < 10; ++i)
  107. {
  108. pool.construct();
  109. }
  110. }
  111. {
  112. // Construct several tester objects. Delete some of them.
  113. boost::object_pool<tester> pool;
  114. std::vector<tester *> v;
  115. for(int i=0; i < 10; ++i)
  116. {
  117. v.push_back(pool.construct());
  118. }
  119. pool_test_random_shuffle(v.begin(), v.end());
  120. for(int j=0; j < 5; ++j)
  121. {
  122. pool.destroy(v[j]);
  123. }
  124. }
  125. {
  126. // Test how pool reacts with constructors that throw exceptions.
  127. // Shouldn't have any memory leaks.
  128. boost::object_pool<tester> pool;
  129. for(int i=0; i < 5; ++i)
  130. {
  131. pool.construct();
  132. }
  133. for(int j=0; j < 5; ++j)
  134. {
  135. try
  136. {
  137. // The following constructions will raise an exception.
  138. pool.construct(true);
  139. }
  140. catch(const std::logic_error &) {}
  141. }
  142. }
  143. }
  144. void test_alloc()
  145. {
  146. {
  147. // Allocate several tester objects. Delete one.
  148. std::vector<tester, boost::pool_allocator<tester> > l;
  149. for(int i=0; i < 10; ++i)
  150. {
  151. l.push_back(tester());
  152. }
  153. l.pop_back();
  154. }
  155. {
  156. // Allocate several tester objects. Delete two.
  157. std::deque<tester, boost::pool_allocator<tester> > l;
  158. for(int i=0; i < 10; ++i)
  159. {
  160. l.push_back(tester());
  161. }
  162. l.pop_back();
  163. l.pop_front();
  164. }
  165. {
  166. // Allocate several tester objects. Delete two.
  167. std::list<tester, boost::fast_pool_allocator<tester> > l;
  168. // lists rebind their allocators, so dumping is useless
  169. for(int i=0; i < 10; ++i)
  170. {
  171. l.push_back(tester());
  172. }
  173. l.pop_back();
  174. l.pop_front();
  175. }
  176. tester * tmp;
  177. {
  178. // Create a memory leak on purpose. (Allocator doesn't have
  179. // garbage collection)
  180. // (Note: memory leak)
  181. boost::pool_allocator<tester> a;
  182. tmp = a.allocate(1, 0);
  183. new (tmp) tester();
  184. }
  185. if(mem.ok())
  186. {
  187. BOOST_ERROR("Pool allocator cleaned up itself");
  188. }
  189. // Remove memory checker entry (to avoid error later) and
  190. // clean up memory leak
  191. tmp->~tester();
  192. boost::pool_allocator<tester>::deallocate(tmp, 1);
  193. // test allocating zero elements
  194. {
  195. boost::pool_allocator<tester> alloc;
  196. tester* ip = alloc.allocate(0);
  197. alloc.deallocate(ip, 0);
  198. }
  199. }
  200. void test_mem_usage()
  201. {
  202. typedef boost::pool<track_alloc> pool_type;
  203. {
  204. // Constructor should do nothing; no memory allocation
  205. pool_type pool(sizeof(int));
  206. BOOST_TEST(track_alloc::ok());
  207. BOOST_TEST(!pool.release_memory());
  208. BOOST_TEST(!pool.purge_memory());
  209. // Should allocate from system
  210. pool.free(pool.malloc());
  211. BOOST_TEST(!track_alloc::ok());
  212. // Ask pool to give up memory it's not using; this should succeed
  213. BOOST_TEST(pool.release_memory());
  214. BOOST_TEST(track_alloc::ok());
  215. // Should allocate from system again
  216. pool.malloc(); // loses the pointer to the returned chunk (*A*)
  217. // Ask pool to give up memory it's not using; this should fail
  218. BOOST_TEST(!pool.release_memory());
  219. // Force pool to give up memory it's not using; this should succeed
  220. // This will clean up the memory leak from (*A*)
  221. BOOST_TEST(pool.purge_memory());
  222. BOOST_TEST(track_alloc::ok());
  223. // Should allocate from system again
  224. pool.malloc(); // loses the pointer to the returned chunk (*B*)
  225. // pool's destructor should purge the memory
  226. // This will clean up the memory leak from (*B*)
  227. }
  228. BOOST_TEST(track_alloc::ok());
  229. }
  230. void test_void()
  231. {
  232. typedef boost::pool_allocator<void> void_allocator;
  233. typedef boost::fast_pool_allocator<void> fast_void_allocator;
  234. typedef void_allocator::rebind<int>::other int_allocator;
  235. typedef fast_void_allocator::rebind<int>::other fast_int_allocator;
  236. std::vector<int, int_allocator> v1;
  237. std::vector<int, fast_int_allocator> v2;
  238. }
  239. int main()
  240. {
  241. std::srand(static_cast<unsigned>(std::time(0)));
  242. test();
  243. test_alloc();
  244. test_mem_usage();
  245. test_void();
  246. return boost::report_errors();
  247. }