Advertisement
Guest User

Untitled

a guest
Mar 18th, 2018
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.88 KB | None | 0 0
  1. /*
  2. =============================================================================
  3.     File:   Memory.h
  4.     Desc:   Memory management.
  5.     ToDo:   Memory limits and watchdogs, thread-safety,
  6.             allow users to define their own OutOfMemory handlers, etc.
  7. =============================================================================
  8. */
  9. #pragma once
  10.  
  11. //@todo: remove it from here
  12. #include <Base/Object/EnumType.h>   // for MemoryHeapT
  13. //#include <Base/Template/SmartPtr/TPtr.h>
  14. #include <Base/Template/Containers/Array/TStaticArray.h>
  15.  
  16. //---------------------------------------------------------------------------
  17. //      Defines.
  18. //---------------------------------------------------------------------------
  19.  
  20. // 1 - Track each memory allocation/deallocation, record memory usage statistics and detect memory leaks and so on.
  21. #define MX_DEBUG_MEMORY         MX_DEBUG
  22.  
  23. // 1 - Redirect the global 'new' and 'delete' to our memory manager.
  24. // this is dangerous, it may be better to define them on per-type basis or use special macros.
  25. #define MX_OVERRIDE_GLOBAL_NEWDELETE    (0)
  26.  
  27. // 1 - prevent the programmer from using malloc/free.
  28. #define MX_HIDE_MALLOC_AND_FREE     (0)
  29.  
  30. //---------------------------------------------------------------------------
  31. //      Declarations.
  32. //---------------------------------------------------------------------------
  33.  
  34. class mxClass;
  35.  
  36. // memory heaps/arenas/areas
  37. // split by size/lifetime
  38. enum EMemoryHeap
  39. {
  40. #define DECLARE_MEMORY_HEAP( NAME )     Heap##NAME
  41. #include <Base/Memory/MemoryHeaps.inl>
  42. #undef DECLARE_MEMORY_HEAP
  43.  
  44.     HeapCount,  //!<= Marker. Don't use.
  45. };
  46. mxDECLARE_ENUM( EMemoryHeap, UINT8, MemoryHeapT );
  47.  
  48. mxSTOLEN("based on Bitsquid foundation library");
  49. /// Base class for memory allocators.
  50. ///
  51. /// Note: Regardless of which allocator is used, prefer to allocate memory in larger chunks
  52. /// instead of in many small allocations. This helps with data locality, fragmentation,
  53. /// memory usage tracking, etc.
  54. ///
  55. /// NOTE: ideally, 'dynamically-resizing' containers and the associated memory manager
  56. /// should know about each other to efficiently work together.
  57. /// We could pass the size of allocated memory to the Free() function (like STL allocators),
  58. /// but this optimization is usually avoided in practice (a new source of bugs).
  59. ///
  60. /// Memory allocations/deallocations are expensive operations
  61. /// so use of virtual member functions should be ok.
  62. ///
  63. struct AHeap : NonCopyable
  64. {
  65.     /// Allocates the specified amount of memory aligned to the specified alignment.
  66.     virtual void* Allocate( U32 _bytes, U32 _alignment ) = 0;
  67.  
  68.     /// Frees an allocation previously made with Allocate().
  69.     ///@todo: pass the allocated size as an optimization?
  70.     virtual void Deallocate( void* _memory ) = 0;
  71.  
  72.     /// Returns the amount of usable memory allocated at _memory. _memory must be a pointer
  73.     /// returned by Allocate() that has not yet been deallocated. The value returned
  74.     /// will be at least the size specified to Allocate(), but it can be bigger.
  75.     /// (The allocator may round up the allocation to fit into a set of predefined
  76.     /// slot sizes.)
  77.     ///
  78.     /// Not all allocators support tracking the size of individual allocations.
  79.     /// An allocator that doesn't support it will return SIZE_NOT_TRACKED.
  80.     virtual U32 allocated_size( const void* _memory ) const
  81.     {
  82.         return SIZE_NOT_TRACKED;
  83.     }
  84.  
  85. public:
  86.     /// Returns the total amount of memory allocated by this allocator. Note that the
  87.     /// size returned can be bigger than the size of all individual allocations made,
  88.     /// because the allocator may keep additional structures.
  89.     ///
  90.     /// If the allocator doesn't track memory, this function returns SIZE_NOT_TRACKED.
  91.     virtual U32 total_allocated() const
  92.     {
  93.         return SIZE_NOT_TRACKED;
  94.     }
  95.  
  96.     virtual void Validate() {}; // verify heap (debug mode only)
  97.     virtual void Optimize() {}; // compact heap
  98.  
  99.     /// writes memory statistics, usage & leak info to the specified file
  100.     virtual void Dump( ALog& log ) {};
  101.  
  102.     /// \return The name of the allocator implementing this interface
  103.     //virtual const char* GetName() const { return mxSTRING_Unknown; }
  104.  
  105.     /// A return value indicating that 'the size is not tracked'.
  106.     static const U32 SIZE_NOT_TRACKED = 0;
  107.  
  108. protected:
  109.     AHeap() {}
  110.     virtual ~AHeap() {}
  111.  
  112.     /// Allocators cannot be copied.
  113.     PREVENT_COPY(AHeap);
  114. };
  115.  
  116. extern TStaticArray< AHeap*, HeapCount >    g_heaps;
  117.  
  118. ERet Memory_Initialize();
  119. void Memory_Shutdown(); // shutdown and assert on memory leaks
  120.  
  121. namespace Heaps
  122. {
  123.  
  124. /// thread-safe ring buffer allocator, can be used for passing data between threads
  125. inline AHeap& scratch() { return *g_heaps[HeapTemporary]; }
  126.  
  127. /// default, generic heap
  128. inline AHeap& global() { return *g_heaps[HeapGeneric]; }
  129.  
  130. void DumpStats();
  131.  
  132. }//namespace Heaps
  133.  
  134. //---------------------------------------------------------------------------
  135. //      HELPER MACROS
  136. //---------------------------------------------------------------------------
  137.  
  138. #define mxALLOC( size, align )          (g_heaps[HeapGeneric]->Allocate( (size), (align) ))
  139. #define mxFREE( memory, size )          (g_heaps[HeapGeneric]->Deallocate( (memory)/*, (size)*/ ))
  140.  
  141. /// declare our own 'new' and 'delete' so that these can be found via 'find All References'
  142.  
  143. #if defined(new_one) || defined(free_one)
  144. #   error 'new_one' and 'free_one' have already been  defined - shouldn't happen!
  145. #endif
  146.  
  147. #define new_one( x )    new x
  148. #define free_one( x )   delete x
  149.  
  150. // Array operators
  151.  
  152. #if defined(new_array) || defined(free_array)
  153. #   error 'new_array' and 'free_array' have already been defined - shouldn't happen!
  154. #endif
  155.  
  156. #define new_array( x, num )     new x [num]
  157. #define free_array( x )         delete[] x
  158.  
  159. #if MX_OVERRIDE_GLOBAL_NEWDELETE
  160.     #error Incompatible options: overriden global 'new' and 'delete' and per-class memory heaps.
  161. #endif
  162.  
  163. //
  164. //  mxDECLARE_CLASS_ALLOCATOR
  165. //
  166. //  'className' can be used to track instances of the class.
  167. //
  168. #define mxDECLARE_CLASS_ALLOCATOR( memClass, className )\
  169. public:\
  170.     typedef className THIS_TYPE;    \
  171.     static EMemoryHeap GetHeap() { return memClass; }   \
  172.     mxFORCEINLINE void* operator new      ( size_t sizeInBytes ){ return mxAllocX( memClass, sizeInBytes ); }   \
  173.     mxFORCEINLINE void  operator delete   ( void* ptr )         { mxFreeX( memClass, ptr ); }                   \
  174.     mxFORCEINLINE void* operator new      ( size_t, void* ptr ) { return ptr; }                                 \
  175.     mxFORCEINLINE void  operator delete   ( void*, void* )      { }                                             \
  176.     mxFORCEINLINE void* operator new[]    ( size_t sizeInBytes ){ return mxAllocX( memClass, sizeInBytes ); }   \
  177.     mxFORCEINLINE void  operator delete[] ( void* ptr )         { mxFreeX( memClass, ptr ); }                   \
  178.     mxFORCEINLINE void* operator new[]    ( size_t, void* ptr ) { return ptr; }                                 \
  179.     mxFORCEINLINE void  operator delete[] ( void*, void* )      { }                                             \
  180.  
  181. //
  182. //  mxDECLARE_VIRTUAL_CLASS_ALLOCATOR
  183. //
  184. #define mxDECLARE_VIRTUAL_CLASS_ALLOCATOR( memClass, className )\
  185. public:\
  186.     typedef className THIS_TYPE;    \
  187.     mxFORCEINLINE void* operator new      ( size_t sizeInBytes ){ return mxAllocX( memClass, sizeInBytes ); }   \
  188.     mxFORCEINLINE void  operator delete   ( void* ptr )         { mxFreeX( memClass, ptr ); }                   \
  189.     mxFORCEINLINE void* operator new      ( size_t, void* ptr ) { return ptr; }                                 \
  190.     mxFORCEINLINE void  operator delete   ( void*, void* )      { }                                             \
  191.     mxFORCEINLINE void* operator new[]    ( size_t sizeInBytes ){ return mxAllocX( memClass, sizeInBytes ); }   \
  192.     mxFORCEINLINE void  operator delete[] ( void* ptr )         { mxFreeX( memClass, ptr ); }                   \
  193.     mxFORCEINLINE void* operator new[]    ( size_t, void* ptr ) { return ptr; }                                 \
  194.     mxFORCEINLINE void  operator delete[] ( void*, void* )      { }
  195.  
  196. //
  197. //  mxDECLARE_NONVIRTUAL_CLASS_ALLOCATOR
  198. //
  199. #define mxDECLARE_NONVIRTUAL_CLASS_ALLOCATOR( memClass, className )\
  200. public:\
  201.     typedef className THIS_TYPE;    \
  202.     mxFORCEINLINE void* operator new      ( size_t sizeInBytes ){ return mxAllocX( memClass, sizeInBytes ); }   \
  203.     mxFORCEINLINE void  operator delete   ( void* ptr )         { mxFreeX( memClass, ptr ); }                   \
  204.     mxFORCEINLINE void* operator new      ( size_t, void* ptr ) { return ptr; }                                 \
  205.     mxFORCEINLINE void  operator delete   ( void*, void* )      { }                                             \
  206.     mxFORCEINLINE void* operator new[]    ( size_t sizeInBytes ){ return mxAllocX( memClass, sizeInBytes ); }   \
  207.     mxFORCEINLINE void  operator delete[] ( void* ptr )         { mxFreeX( memClass, ptr ); }                   \
  208.     mxFORCEINLINE void* operator new[]    ( size_t, void* ptr ) { return ptr; }                                 \
  209.     mxFORCEINLINE void  operator delete[] ( void*, void* )      { }
  210.  
  211. //---------------------------------------------------------------------------
  212. //      Prevent usage of plain old 'malloc' & 'free' if needed.
  213. //---------------------------------------------------------------------------
  214.  
  215. #if MX_HIDE_MALLOC_AND_FREE
  216.  
  217.     #define malloc( size )          ptBREAK
  218.     #define free( mem )             ptBREAK
  219.     #define calloc( num, size )     ptBREAK
  220.     #define realloc( mem, newsize ) ptBREAK
  221.  
  222. #endif // MX_HIDE_MALLOC_AND_FREE
  223.  
  224. //------------------------------------------------------------------------
  225. //  Useful macros
  226. //------------------------------------------------------------------------
  227.  
  228. #ifndef SAFE_DELETE
  229. #define SAFE_DELETE( p )        { if( p != nil ) { delete (p);     (p) = nil; } }
  230. #endif
  231.  
  232. #ifndef SAFE_DELETE_ARRAY
  233. #define SAFE_DELETE_ARRAY( p )  { if( p != nil ) { delete[] (p);   (p) = nil; } }
  234. #endif
  235.  
  236. #define mxNULLIFY_POINTER(p)    {(p) = nil;}
  237.  
  238.  
  239.  
  240. #if 0 // mxSUPPORTS_VARIADIC_TEMPLATES
  241.  
  242.     /// Creates a new object of the given type using the specified allocator.
  243.     template< typename TYPE, typename... ARGs >
  244.     TYPE* mxNEW( AHeap& _heap, ARGs&&... _args )
  245.     {
  246.         void * storage = _heap.Allocate( sizeof(TYPE), mxALIGNOF(TYPE) );
  247.         return new(storage) TYPE( std::forward< ARGs >(_args)... );
  248.     }
  249.  
  250. #else
  251.  
  252.     /// Creates a new object of the given type using the specified allocator.
  253.     #define mxNEW( HEAP, TYPE, ... )\
  254.         (new\
  255.             ((HEAP).Allocate( sizeof(TYPE), GET_ALIGNMENT_FOR_CONTAINERS(TYPE) ))\
  256.                 TYPE(__VA_ARGS__))
  257.  
  258. #endif
  259.  
  260.     /// Frees an object allocated with mxNEW.
  261.     template< typename TYPE, class HEAP >
  262.     void mxDELETE( HEAP& _heap, TYPE* _o )
  263.     {
  264.         if( _o != nullptr ) {
  265.             _o->~TYPE();
  266.             _heap.Deallocate( _o );
  267.         }
  268.     }
  269.  
  270. ///
  271. #define mxTRY_ALLOC_SCOPED( _VAR, _ARRAY_COUNT, _ALLOCATOR )\
  272.     mxDO( __TryAllocate( _VAR, _ARRAY_COUNT, _ALLOCATOR ) );\
  273.     AutoFree __autofree##_VAR##__LINE__( _ALLOCATOR, _VAR );
  274.  
  275. /// internal function used by the mxTRY_ALLOC_SCOPED macro
  276. template< typename TYPE >
  277. ERet __TryAllocate( TYPE *& _pointer, U32 _count, AHeap &_allocator )
  278. {
  279.     TYPE* p = static_cast< TYPE* >( _allocator.Allocate( sizeof(TYPE)*_count, GET_ALIGNMENT_FOR_CONTAINERS(TYPE) ) );
  280.     if( !p ) {
  281.         return ERR_OUT_OF_MEMORY;
  282.     }
  283.     _pointer = p;
  284.     return ALL_OK;
  285. }
  286.  
  287. /// automatically frees pointed memory; used internally by the mxTRY_ALLOC_SCOPED macro
  288. class AutoFree {
  289.     AHeap & m_heap;
  290.     void *  m_memory;
  291. public:
  292.     AutoFree( AHeap & _heap, void* _memory )
  293.         : m_heap( _heap ), m_memory( _memory )
  294.     {}
  295.     ~AutoFree() {
  296.         m_heap.Deallocate( m_memory );
  297.     }
  298. };
  299.  
  300. /// renders any heap thread-safe
  301. class ThreadSafeProxyHeap : public AHeap
  302. {
  303.     mutable SpinWait    m_lock;
  304.     AHeap & m_heap; //!< the actual allocator we're using under the hood
  305. public:
  306.     ThreadSafeProxyHeap( AHeap &_heap )
  307.         : m_heap( _heap )
  308.     {
  309.     }
  310.     ERet Initialize()
  311.     {
  312.         m_lock.Initialize();
  313.         return ALL_OK;
  314.     }
  315.     void Shutdown()
  316.     {
  317.         m_lock.Shutdown();
  318.     }
  319.     virtual void* Allocate( U32 _bytes, U32 _alignment ) override
  320.     {
  321.         mxASSERT(_bytes > 0);
  322.         SpinWait::Lock  scopedLock( m_lock );
  323.         void* result = m_heap.Allocate( _bytes, _alignment );
  324.         return result;
  325.     }
  326.     virtual void Deallocate( void* _memory ) override
  327.     {
  328.         if( _memory ) {
  329.             SpinWait::Lock  scopedLock( m_lock );
  330.             m_heap.Deallocate( (void*)_memory );
  331.         }
  332.     }
  333.     virtual U32 allocated_size( const void* _memory ) const
  334.     {
  335.         SpinWait::Lock  scopedLock( m_lock );
  336.         return m_heap.allocated_size( _memory );
  337.     }
  338. };
  339.  
  340. /// _aligned_malloc/_aligned_free
  341. class DefaultHeap : public AHeap
  342. {
  343. public:
  344.     DefaultHeap();
  345.     virtual void* Allocate( U32 _bytes, U32 _alignment ) override;
  346.     virtual void Deallocate( void* _memory ) override;
  347.     virtual U32 allocated_size( const void* _memory ) const override;
  348. };
  349.  
  350.   /// A proxy allocator that simply draws upon another allocator.
  351.   /// http://bitsquid.blogspot.ru/2010/09/custom-memory-allocation-in-c.html
  352.   class TrackingHeap : public AHeap {
  353.       AHeap & m_allocator;
  354.   public:
  355.       TrackingHeap( const char* _name, AHeap & _allocator )
  356.       : m_allocator( _allocator )
  357.     {}
  358.       virtual void* Allocate( U32 _bytes, U32 _alignment ) override {
  359.       return m_allocator.Allocate( _bytes, _alignment );
  360.     }
  361.       virtual void Deallocate( void* _memory ) override {
  362.       m_allocator.Deallocate( _memory );
  363.     }
  364.       virtual U32   allocated_size( const void* _memory ) const override {
  365.       return m_allocator.allocated_size( _memory );
  366.     }
  367.   };
  368.  
  369. //--------------------------------------------------------------//
  370. //              End Of File.                                    //
  371. //--------------------------------------------------------------//
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement