BsMemoryAllocator.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. #pragma once
  2. #undef min
  3. #undef max
  4. #include <atomic>
  5. /** @addtogroup Memory
  6. * @{
  7. */
  8. namespace BansheeEngine
  9. {
  10. class MemoryAllocatorBase;
  11. /** @cond INTERNAL */
  12. /**
  13. * Thread safe class used for storing total number of memory allocations and deallocations, primarily for statistic
  14. * purposes.
  15. */
  16. class MemoryCounter
  17. {
  18. public:
  19. static BS_UTILITY_EXPORT UINT64 getNumAllocs()
  20. {
  21. return Allocs;
  22. }
  23. static BS_UTILITY_EXPORT UINT64 getNumFrees()
  24. {
  25. return Frees;
  26. }
  27. private:
  28. friend class MemoryAllocatorBase;
  29. // Threadlocal data can't be exported, so some magic to make it accessible from MemoryAllocator
  30. static BS_UTILITY_EXPORT void incAllocCount() { Allocs++; }
  31. static BS_UTILITY_EXPORT void incFreeCount() { Frees++; }
  32. static BS_THREADLOCAL UINT64 Allocs;
  33. static BS_THREADLOCAL UINT64 Frees;
  34. };
  35. /** Base class all memory allocators need to inherit. Provides allocation and free counting. */
  36. class MemoryAllocatorBase
  37. {
  38. protected:
  39. static void incAllocCount() { MemoryCounter::incAllocCount(); }
  40. static void incFreeCount() { MemoryCounter::incFreeCount(); }
  41. };
  42. /**
  43. * Memory allocator providing a generic implementation. Specialize for specific categories as needed.
  44. *
  45. * @note For example you might implement a pool allocator for specific types in order
  46. * to reduce allocation overhead. By default standard malloc/free are used.
  47. */
  48. template<class T>
  49. class MemoryAllocator : public MemoryAllocatorBase
  50. {
  51. public:
  52. static void* allocate(size_t bytes)
  53. {
  54. #if BS_PROFILING_ENABLED
  55. incAllocCount();
  56. #endif
  57. return malloc(bytes);
  58. }
  59. static void* allocateArray(size_t bytes, UINT32 count)
  60. {
  61. #if BS_PROFILING_ENABLED
  62. incAllocCount();
  63. #endif
  64. return malloc(bytes * count);
  65. }
  66. static void free(void* ptr)
  67. {
  68. #if BS_PROFILING_ENABLED
  69. incFreeCount();
  70. #endif
  71. ::free(ptr);
  72. }
  73. static void freeArray(void* ptr, UINT32 count)
  74. {
  75. #if BS_PROFILING_ENABLED
  76. incFreeCount();
  77. #endif
  78. ::free(ptr);
  79. }
  80. };
  81. /**
  82. * General allocator provided by the OS. Use for persistent long term allocations, and allocations that don't
  83. * happen often.
  84. */
  85. class GenAlloc
  86. { };
  87. /** @endcond */
  88. /** Allocates the specified number of bytes. */
  89. template<class Alloc>
  90. inline void* bs_alloc(UINT32 count)
  91. {
  92. return MemoryAllocator<Alloc>::allocate(count);
  93. }
  94. /** Allocates enough bytes to hold the specified type, but doesn't construct it. */
  95. template<class T, class Alloc>
  96. inline T* bs_alloc()
  97. {
  98. return (T*)MemoryAllocator<Alloc>::allocate(sizeof(T));
  99. }
  100. /** Creates and constructs an array of @p count elements. */
  101. template<class T, class Alloc>
  102. inline T* bs_newN(UINT32 count)
  103. {
  104. T* ptr = (T*)MemoryAllocator<Alloc>::allocateArray(sizeof(T), count);
  105. for(unsigned int i = 0; i < count; i++)
  106. new ((void*)&ptr[i]) T;
  107. return ptr;
  108. }
  109. /** Create a new object with the specified allocator and the specified parameters. */
  110. template<class Type, class Alloc, class... Args>
  111. Type* bs_new(Args &&...args)
  112. {
  113. return new (bs_alloc<Alloc>(sizeof(Type))) Type(std::forward<Args>(args)...);
  114. }
  115. /** Frees all the bytes allocated at the specified location. */
  116. template<class Alloc>
  117. inline void bs_free(void* ptr)
  118. {
  119. MemoryAllocator<Alloc>::free(ptr);
  120. }
  121. /** Destructs and frees the specified object. */
  122. template<class T, class Alloc = GenAlloc>
  123. inline void bs_delete(T* ptr)
  124. {
  125. (ptr)->~T();
  126. MemoryAllocator<Alloc>::free(ptr);
  127. }
  128. /** Destructs and frees the specified array of objects. */
  129. template<class T, class Alloc = GenAlloc>
  130. inline void bs_deleteN(T* ptr, UINT32 count)
  131. {
  132. for(unsigned int i = 0; i < count; i++)
  133. ptr[i].~T();
  134. MemoryAllocator<Alloc>::freeArray(ptr, count);
  135. }
  136. /*****************************************************************************/
  137. /* Default versions of all alloc/free/new/delete methods which call GenAlloc */
  138. /*****************************************************************************/
  139. /** Allocates the specified number of bytes. */
  140. inline void* bs_alloc(UINT32 count)
  141. {
  142. return MemoryAllocator<GenAlloc>::allocate(count);
  143. }
  144. /** Allocates enough bytes to hold the specified type, but doesn't construct it. */
  145. template<class T>
  146. inline T* bs_alloc()
  147. {
  148. return (T*)MemoryAllocator<GenAlloc>::allocate(sizeof(T));
  149. }
  150. /** Allocates enough bytes to hold an array of @p count elements the specified type, but doesn't construct them. */
  151. template<class T>
  152. inline T* bs_allocN(UINT32 count)
  153. {
  154. return (T*)MemoryAllocator<GenAlloc>::allocate(count * sizeof(T));
  155. }
  156. /** Creates and constructs an array of @p count elements. */
  157. template<class T>
  158. inline T* bs_newN(UINT32 count)
  159. {
  160. T* ptr = (T*)MemoryAllocator<GenAlloc>::allocateArray(sizeof(T), count);
  161. for(unsigned int i = 0; i < count; i++)
  162. new ((void*)&ptr[i]) T;
  163. return ptr;
  164. }
  165. /** Create a new object with the specified allocator and the specified parameters. */
  166. template<class Type, class... Args>
  167. Type* bs_new(Args &&...args)
  168. {
  169. return new (bs_alloc<GenAlloc>(sizeof(Type))) Type(std::forward<Args>(args)...);
  170. }
  171. /** Frees all the bytes allocated at the specified location. */
  172. inline void bs_free(void* ptr)
  173. {
  174. MemoryAllocator<GenAlloc>::free(ptr);
  175. }
  176. /************************************************************************/
  177. /* MACRO VERSIONS */
  178. /* You will almost always want to use the template versions but in some */
  179. /* cases (private destructor) it is not possible. In which case you may */
  180. /* use these instead. */
  181. /************************************************************************/
  182. #define BS_PVT_DELETE(T, ptr) \
  183. (ptr)->~T(); \
  184. MemoryAllocator<GenAlloc>::free(ptr);
  185. #define BS_PVT_DELETE_A(T, ptr, Alloc) \
  186. (ptr)->~T(); \
  187. MemoryAllocator<Alloc>::free(ptr);
  188. }
  189. namespace BansheeEngine
  190. {
  191. /** @cond INTERNAL */
  192. /** Allocator for the standard library that internally uses Banshee memory allocator. */
  193. template <class T, class Alloc = GenAlloc>
  194. class StdAlloc
  195. {
  196. public:
  197. typedef T value_type;
  198. StdAlloc() noexcept {}
  199. template<class T, class Alloc> StdAlloc(const StdAlloc<T, Alloc>&) noexcept {}
  200. template<class T, class Alloc> bool operator==(const StdAlloc<T, Alloc>&) const noexcept { return true; }
  201. template<class T, class Alloc> bool operator!=(const StdAlloc<T, Alloc>&) const noexcept { return false; }
  202. /** Allocate but don't initialize number elements of type T. */
  203. T* allocate(const size_t num) const
  204. {
  205. if (num == 0)
  206. return nullptr;
  207. if (num > static_cast<size_t>(-1) / sizeof(T))
  208. throw std::bad_array_new_length();
  209. void* const pv = bs_alloc<Alloc>((UINT32)(num * sizeof(T)));
  210. if (!pv)
  211. throw std::bad_alloc();
  212. return static_cast<T*>(pv);
  213. }
  214. /** Deallocate storage p of deleted elements. */
  215. void deallocate(T* p, size_t num) const noexcept
  216. {
  217. bs_free<Alloc>((void*)p);
  218. }
  219. };
  220. /** @endcond */
  221. }
  222. /** @} */
  223. #include "BsMemStack.h"
  224. #include "BsGlobalFrameAlloc.h"
  225. #include "BsMemAllocProfiler.h"