Ogre内存分配器分析(1)

#ifndef __AllocatedObject_H__

#define __AllocatedObject_H__

#include "OgrePrerequisites.h"  //平台定义,包含所有调试模式,引擎版本,VC++版本,常用基本类型重定义,

                                                            多线程使用声明,引擎内主要类声明,Ogre内所用到的std头文件包含进来

                                                            包含Ogre的内存分配OgreMemoryAllocatorConfig.h,重定义了std::string和std::wstring和对应流的内存分配器,

                                                             重定义了string的基本成员,重新定义了标准库基本容器.

#ifdef new
#  undef new
#endif
#ifdef delete
#  undef delete
#endif

namespace Ogre
{

 template <class Alloc>
class _OgreExport AllocatedObject
{  
public:


explicit AllocatedObject()
{ }


~AllocatedObject()
{ }


  /// operator new, with debug line info
void* operator new(size_t sz, const char* file, int line, const char* func)
{
return Alloc::allocateBytes(sz, file, line, func);
}


 void* operator new(size_t sz)
{
return Alloc::allocateBytes(sz);
}


 /// placement operator new  使用方法见我博客new专题
void* operator new(size_t sz, void* ptr)
{
(void) sz;
return ptr;
}


/// array operator new, with debug line info
void* operator new[] ( size_t sz, const char* file, int line, const char* func )
{
return Alloc::allocateBytes(sz, file, line, func);
}

             

void* operator new[] ( size_t sz )
{
return Alloc::allocateBytes(sz);
}


 void operator delete( void* ptr )
{
Alloc::deallocateBytes(ptr);
}

                 

 // Corresponding operator for placement delete (second param same as the first)
void operator delete( void* ptr, void* )
{
Alloc::deallocateBytes(ptr);
}

               

 // only called if there is an exception in corresponding 'new'
void operator delete( void* ptr, const char* , int , const char*  )
{
Alloc::deallocateBytes(ptr);
}

                

void operator delete[] ( void* ptr )
{
Alloc::deallocateBytes(ptr);
}


void operator delete[] ( void* ptr, const char* , int , const char*  )
{
Alloc::deallocateBytes(ptr);
}

};

}

#endif

以上定义了AllocatedObject类模板,实际类型分析如下


class _OgreExport  NedPoolingPolicy
{
public:
static inline void* allocateBytes(size_t count, const char* file = 0, int line = 0, const char* func = 0)
{
return NedPoolingImpl::allocBytes(count, file, line, func);
}


static inline void deallocateBytes(void* ptr)
{
NedPoolingImpl::deallocBytes(ptr);
}


/// Get the maximum size of a single allocation
static inline size_t getMaxAllocationSize()
{
return std::numeric_limits<size_t>::max();
}

private:
// No instantiation
NedPoolingPolicy()
{ }
};


  class _OgreExport NedPoolingImpl
{
public:
static void* allocBytes(size_t count, const char* file, int line, const char* func);


static void deallocBytes(void* ptr);


static void* allocBytesAligned(size_t align, size_t count, const char* file, int line, const char* func);


static void deallocBytesAligned(size_t align, void* ptr);
};


      下面是真正的Ogre使用Ned库实现内存分配的代码

     // include ned implementation 

     #include <nedmalloc.c> 


      namespace Ogre
      {
namespace _NedPoolingIntern
{
const size_t s_poolCount = 14; // Needs to be greater than 4


void* s_poolFootprint = reinterpret_cast<void*>(0xBB1AA45A);


nedalloc::nedpool* s_pools[s_poolCount + 1] = { 0 };

                 
nedalloc::nedpool* s_poolsAligned[s_poolCount + 1] = { 0 };

size_t poolIDFromSize(size_t a_reqSize)
{
// Requests size 16 or smaller are allocated at a 4 byte granularity.
// Requests size 17 or larger are allocated at a 16 byte granularity.
// With a s_poolCount of 14, requests size 177 or larger go in the default pool.

// spreadsheet style =IF(B35<=16; FLOOR((B35-1)/4;1); MIN(FLOOR((B35-1)/16; 1) + 3; 14))

size_t poolID = 0;

if (a_reqSize > 0)
{
if (a_reqSize <= 16)
{
poolID = (a_reqSize - 1) >> 2;
}
else
{
poolID = std::min<size_t>(((a_reqSize - 1) >> 4) + 3, s_poolCount);
}
}

return poolID;
}


void* internalAlloc(size_t a_reqSize)
{
size_t poolID = poolIDFromSize(a_reqSize);
nedalloc::nedpool* pool(0); // A pool pointer of 0 means the default pool.


if (poolID < s_poolCount)
{
if (s_pools[poolID] == 0)
{
// Init pool if first use


s_pools[poolID] = nedalloc::nedcreatepool(0, 8);
nedalloc::nedpsetvalue(s_pools[poolID], s_poolFootprint); // All pools are stamped with a footprint
}


pool = s_pools[poolID];
}


return nedalloc::nedpmalloc(pool, a_reqSize);
}


void* internalAllocAligned(size_t a_align, size_t a_reqSize)
{
size_t poolID = poolIDFromSize(a_reqSize);
nedalloc::nedpool* pool(0); // A pool pointer of 0 means the default pool.


if (poolID < s_poolCount)
{
if (s_poolsAligned[poolID] == 0)
{
// Init pool if first use


s_poolsAligned[poolID] = nedalloc::nedcreatepool(0, 8);
nedalloc::nedpsetvalue(s_poolsAligned[poolID], s_poolFootprint); // All pools are stamped with a footprint
}


pool = s_poolsAligned[poolID];
}


return nedalloc::nedpmemalign(pool, a_align, a_reqSize);
}


void internalFree(void* a_mem)
{
if (a_mem)
{
nedalloc::nedpool* pool(0);


// nedalloc lets us get the pool pointer from the memory pointer
void* footprint = nedalloc::nedgetvalue(&pool, a_mem);


// Check footprint
if (footprint == s_poolFootprint)
{
// If we allocated the pool, deallocate from this pool...
nedalloc::nedpfree(pool, a_mem);
}
else
{
// ...otherwise let nedalloc handle it.
nedalloc::nedfree(a_mem);
}
}
}
}


//---------------------------------------------------------------------
void* NedPoolingImpl::allocBytes(size_t count, 
const char* file, int line, const char* func)
{
void* ptr = _NedPoolingIntern::internalAlloc(count);
#if OGRE_MEMORY_TRACKER
MemoryTracker::get()._recordAlloc(ptr, count, 0, file, line, func);
#else
// avoid unused params warning
file = func = "";
        line = 0;
#endif
return ptr;
}


//---------------------------------------------------------------------
void NedPoolingImpl::deallocBytes(void* ptr)
{
// deal with null
if (!ptr)
return;
#if OGRE_MEMORY_TRACKER
MemoryTracker::get()._recordDealloc(ptr);
#endif
_NedPoolingIntern::internalFree(ptr);
}


//---------------------------------------------------------------------
void* NedPoolingImpl::allocBytesAligned(size_t align, size_t count, 
const char* file, int line, const char* func)
{
// default to platform SIMD alignment if none specified
void* ptr =  align ? _NedPoolingIntern::internalAllocAligned(align, count)
: _NedPoolingIntern::internalAllocAligned(OGRE_SIMD_ALIGNMENT, count);
#if OGRE_MEMORY_TRACKER
MemoryTracker::get()._recordAlloc(ptr, count, 0, file, line, func);
#else
// avoid unused params warning
file = func = "";
        line = 0;
#endif
return ptr;
}


//---------------------------------------------------------------------
void NedPoolingImpl::deallocBytesAligned(size_t align, void* ptr)
{
// deal with null
if (!ptr)
return;
#if OGRE_MEMORY_TRACKER
MemoryTracker::get()._recordDealloc(ptr);
#endif
_NedPoolingIntern::internalFree(ptr);
}

}


#endif

 

template <MemoryCategory Cat> class CategorisedAllocPolicy : public NedPoolingPolicy{};之一

typedef CategorisedAllocPolicy<Ogre::MEMCATEGORY_GENERAL> GeneralAllocPolicy;之二

typedef AllocatedObject<GeneralAllocPolicy> GeneralAllocatedObject;之三

typedef GeneralAllocatedObject ArchiveAlloc;之四


除了AllocatorObject定义的operator new 和 operator delete

引擎还留了如下的接口

#if OGRE_DEBUG_MODE

/// Allocate a block of raw memory, and indicate the category of usage
# define OGRE_MALLOC(bytes, category) ::Ogre::CategorisedAllocPolicy<category>::allocateBytes(bytes, __FILE__, __LINE__, __FUNCTION__)


/// Allocate a block of memory for a primitive type, and indicate the category of usage

# define OGRE_ALLOC_T(T, count, category) static_cast<T*>(::Ogre::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__))


/// Free the memory allocated with OGRE_MALLOC or OGRE_ALLOC_T. Category is required to be restated to ensure the matching policy is used

# define OGRE_FREE(ptr, category) ::Ogre::CategorisedAllocPolicy<category>::deallocateBytes((void*)ptr)


/// Allocate space for one primitive type, external type or non-virtual type with constructor parameters
# define OGRE_NEW_T(T, category) new (::Ogre::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T), __FILE__, __LINE__, __FUNCTION__)) T


/// Allocate a block of memory for 'count' primitive types - do not use for classes that inherit from AllocatedObject

# define OGRE_NEW_ARRAY_T(T, count, category) ::Ogre::constructN(static_cast<T*>(::Ogre::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__)), count) 


/// Free the memory allocated with OGRE_NEW_T. Category is required to be restated to ensure the matching policy is used

# define OGRE_DELETE_T(ptr, T, category) if(ptr){(ptr)->~T(); ::Ogre::CategorisedAllocPolicy<category>::deallocateBytes((void*)ptr);}


/// Free the memory allocated with OGRE_NEW_ARRAY_T. Category is required to be restated to ensure the matching policy is used, count and type to call destructor

# define OGRE_DELETE_ARRAY_T(ptr, T, count, category) if(ptr){for (size_t b = 0; b < count; ++b) { (ptr)[b].~T();} ::Ogre::CategorisedAllocPolicy<category>::deallocateBytes((void*)ptr);}


// aligned allocation
/// Allocate a block of raw memory aligned to SIMD boundaries, and indicate the category of usage
# define OGRE_MALLOC_SIMD(bytes, category) ::Ogre::CategorisedAlignAllocPolicy<category>::allocateBytes(bytes, __FILE__, __LINE__, __FUNCTION__)


/// Allocate a block of raw memory aligned to user defined boundaries, and indicate the category of usage

# define OGRE_MALLOC_ALIGN(bytes, category, align) ::Ogre::CategorisedAlignAllocPolicy<category, align>::allocateBytes(bytes, __FILE__, __LINE__, __FUNCTION__)


/// Allocate a block of memory for a primitive type aligned to SIMD boundaries, and indicate the category of usage

# define OGRE_ALLOC_T_SIMD(T, count, category) static_cast<T*>(::Ogre::CategorisedAlignAllocPolicy<category>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__))


/// Allocate a block of memory for a primitive type aligned to user defined boundaries, and indicate the category of usage

# define OGRE_ALLOC_T_ALIGN(T, count, category, align) static_cast<T*>(::Ogre::CategorisedAlignAllocPolicy<category, align>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__))


/// Free the memory allocated with either OGRE_MALLOC_SIMD or OGRE_ALLOC_T_SIMD. Category is required to be restated to ensure the matching policy is used

# define OGRE_FREE_SIMD(ptr, category) ::Ogre::CategorisedAlignAllocPolicy<category>::deallocateBytes(ptr)


/// Free the memory allocated with either OGRE_MALLOC_ALIGN or OGRE_ALLOC_T_ALIGN. Category is required to be restated to ensure the matching policy is used

# define OGRE_FREE_ALIGN(ptr, category, align) ::Ogre::CategorisedAlignAllocPolicy<category, align>::deallocateBytes(ptr)


/// Allocate space for one primitive type, external type or non-virtual type aligned to SIMD boundaries
# define OGRE_NEW_T_SIMD(T, category) new (::Ogre::CategorisedAlignAllocPolicy<category>::allocateBytes(sizeof(T), __FILE__, __LINE__, __FUNCTION__)) T


/// Allocate a block of memory for 'count' primitive types aligned to SIMD boundaries - do not use for classes that inherit from AllocatedObject

# define OGRE_NEW_ARRAY_T_SIMD(T, count, category) ::Ogre::constructN(static_cast<T*>(::Ogre::CategorisedAlignAllocPolicy<category>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__)), count) 


/// Free the memory allocated with OGRE_NEW_T_SIMD. Category is required to be restated to ensure the matching policy is used

# define OGRE_DELETE_T_SIMD(ptr, T, category) if(ptr){(ptr)->~T(); ::Ogre::CategorisedAlignAllocPolicy<category>::deallocateBytes(ptr);}


/// Free the memory allocated with OGRE_NEW_ARRAY_T_SIMD. Category is required to be restated to ensure the matching policy is used, count and type to call destructor

# define OGRE_DELETE_ARRAY_T_SIMD(ptr, T, count, category) if(ptr){for (size_t b = 0; b < count; ++b) { (ptr)[b].~T();} ::Ogre::CategorisedAlignAllocPolicy<category>::deallocateBytes(ptr);}


/// Allocate space for one primitive type, external type or non-virtual type aligned to user defined boundaries

# define OGRE_NEW_T_ALIGN(T, category, align) new (::Ogre::CategorisedAlignAllocPolicy<category, align>::allocateBytes(sizeof(T), __FILE__, __LINE__, __FUNCTION__)) T


/// Allocate a block of memory for 'count' primitive types aligned to user defined boundaries - do not use for classes that inherit from AllocatedObject

# define OGRE_NEW_ARRAY_T_ALIGN(T, count, category, align) ::Ogre::constructN(static_cast<T*>(::Ogre::CategorisedAlignAllocPolicy<category, align>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__)), count) 


/// Free the memory allocated with OGRE_NEW_T_ALIGN. Category is required to be restated to ensure the matching policy is used

# define OGRE_DELETE_T_ALIGN(ptr, T, category, align) if(ptr){(ptr)->~T(); ::Ogre::CategorisedAlignAllocPolicy<category, align>::deallocateBytes(ptr);}


/// Free the memory allocated with OGRE_NEW_ARRAY_T_ALIGN. Category is required to be restated to ensure the matching policy is used, count and type to call destructor

# define OGRE_DELETE_ARRAY_T_ALIGN(ptr, T, count, category, align) if(ptr){for (size_t _b = 0; _b < count; ++_b) { (ptr)[_b].~T();} ::Ogre::CategorisedAlignAllocPolicy<category, align>::deallocateBytes(ptr);}


// new / delete for classes deriving from AllocatedObject (alignment determined by per-class policy)
// Also hooks up the file/line/function params
// Can only be used with classes that derive from AllocatedObject since customised new/delete needed

# define OGRE_NEW new (__FILE__, __LINE__, __FUNCTION__)

# define OGRE_DELETE delete


namespace Ogre
{

       /** \addtogroup Core
*  @{
*/
/** \addtogroup Memory
*  @{
*/

/** Utility function for constructing an array of objects with placement new,
without using new[] (which allocates an undocumented amount of extra memory
and so isn't appropriate for custom allocators).
*/
template<typename T>
T* constructN(T* basePtr, size_t count)
{
for (size_t i = 0; i < count; ++i)
{
new ((void*)(basePtr+i)) T();
}
return basePtr;
}
/** @} */
/** @} */



/** Function which invokes OGRE_DELETE on a given pointer. 
@remarks
Useful to pass custom deletion policies to external libraries (e. g. boost).
*/

template<typename T>
void deletePtr(T* ptr)
{
OGRE_DELETE ptr;
}


}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值