#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;
}
}