ogre内存管理

来源:互联网 发布:苹果cms模板整站 编辑:程序博客网 时间:2024/06/09 21:19

OGRE内存分配策略相关文件及简述

OGRE提供了自己的内存分配策略,甚至为STL容器提供了新的分配策略,相关文件及简述如下

OgreMemoryAllocatedObject.h  OgreMemoryAllocatedObject.cpp

// 所有使用Ogre内存分配器的类的父类

OgreMemoryAllocatorConfig.h

// 配置内存分配相关规则

OgreMemoryNedAlloc.h  OgreMemoryNedAlloc.cpp

// 使用nedalloc库,定义了类NedAllocPolicyNedAlignedAllocPolicy

OgreMemoryNedPooling.h  OgreMemoryNedPooling.cpp

// 使用nedalloc库,定义了类NedPoolingPolicyNedPoolingAlignedPolicy

OgreMemoryStdAlloc.h

// 定义了类StdAllocPolicyStdAlignedAllocPolicy

// 只是对malloc/free的简单包装

OgreMemorySTLAllocator.h

// STL容器提供的分配器

OgreMemoryTracker.h  OgreMemoryTracker.cpp

// 用于跟踪内存的分配和释放,并统计内存的使用和泄漏情况

// *为避免循环引用,OgreMemoryTracker.h头文件必须在OgrePrerequisites.h引用后引用*

OgreAlignedAllocator.h  OgreAlignedAllocator.cpp

// 提供对齐内存分配函数

对于OGRE中STL容器的内存分配策略的简述:

以下是摘自OgrePrerequisites.h的代码:

template <typename T,typename A = STLAllocator<T,GeneralAllocPolicy> >

struct vector

{

#if OGRE_CONTAINERS_USE_CUSTOM_MEMORY_ALLOCATOR

     typedef typenamestd::vector<T,A> type;   

#else

     typedef typenamestd::vector<T>type;   

#endif

};

如上所示,OGRESTL容器进行了简单的包装,使其默认使用OGRE提供了内存分配策略GeneralAllocPolicy。在

OgreMemoryAllocatorConfig.h头文件中,能够容易找到GeneralAllocPolicy的定义。这样,在使用STL容器时须加“::type”,如Ogre::vector<T>::type,或者照旧使用STL本身的内存分配策略,如std::vector<T>如需要改变STL容器使用的内存策略,则可以按如下方式使用,Ogre::vector<T,STLAllocator<T,CustomPolicy>>::type,其中CustomPolicy为用户指定的内存策略。

OGRE的内存策略配置及如何自定义内存策略


OGRE的内存策略配置

OGRE中默认所有类型使用一致的内存分配策略,并在编译时便决定。在OgreMemoryAllocatorConfig.h文件中由OGRE_MEMORY_ALLOCATOR宏选择相应的内存策略。

OGRE提供了如下三种内存策略:

    NedAllocPolicyNedAlignedAllocPolicy

    NedPoolingPolicyNedPoolingAlignedPolicy

    StdAllocPolicyStdAlignedAllocPolicy

OgreConfig.h中定义有

    #define OGRE_MEMORY_ALLOCATOR_STD 1

    #define OGRE_MEMORY_ALLOCATOR_NED 2

    #define OGRE_MEMORY_ALLOCATOR_NEDPOOLING 4

OgreBuildSettings.h中定义有

    #define OGRE_MEMORY_ALLOCATOR 4

即OGRE默认使用的内存分配策略为NedPoolingPolicy

*** OgreMemoryAllocatorConfig.h文件中定义MemoryCategory枚举类型,以支持不同目的使用不同的内存分配方式,但需用户自己实现。


如何自定义内存分配策略

(假定类名为CustomAllocPolicy,对齐类为CustomAlignAllocPolicy):

1. 在CustomAllocPolicy和CustomAlignAllocPolicy中至少实现如下三个静态函数:

//分配内存

static inline void* allocateBytes(size_t count, const char* file = 0, int line = 0, const char* func = 0);

//释放内存

static inline void deallocateBytes(void* ptr);

//获取一次性分配的最大分配数量

static inline size_t getMaxAllocationSize();

2. 在OgreConfig.h头文件中添加相应宏定义

如  #define OGRE_MEMORY_ALLOCATOR_CUSTOM5

3. OgreMemoryAllocatorConfig.h头文件中添加代码行,如

#elif OGRE_MEMORY_ALLOCATOR == OGRE_MEMORY_ALLOCATOR_CUSTOM

# include "OgreMemoryCustomAlloc.h"  //CustomAllocPolicy类所在头文件

namespace Ogre

{

template <MemoryCategory Cat> class CategorisedAllocPolicy : publicCustomAllocPolicy{};

template <MemoryCategory Cat, size_t align = 0> class CategorisedAlignAllocPolicy : publicCustomAlignAllocPolicy<align>{};

}

4. 最后在OgreBuildSettings.h中改变定义

#define OGRE_MEMORY_ALLOCATOR


如何在程序中使用OGRE提供的内存策略

要使用OGRE提供的内存策略(或自定义的内存策略)主要有两种方式:

1. 继承AllocatedObject

2. 使用OgreMemoryAllocatorConfig.h头文件中定义的内存操作宏


继承AllocatedObject

AllocatedObject类中重载了new、new[]、delete及delete[]等操作符,所以若要A类使用Ogre提供的或自定义的内存策略,只需继承AllocatedObject类即可。AllocatedObject类以模板的形式支持各种内存分配策略。在OgreMemoryAllocatorConfig.h头文件中对各种模板的AllocatedObject类进行了“重命名”,例如:

typedef CategorisedAllocPolicy<Ogre::MEMCATEGORY_GENERAL>GeneralAllocPolicy;

typedef AllocatedObject<GeneralAllocPolicy>GeneralAllocatedObject;

typedef GeneralAllocatedObject  ArchiveAlloc;

typedef GeneralAllocatedObject  ConfigAlloc;

所以在继承使用AllocatedObject类时,可考虑使用OgreMemoryAllocatorConfig.h头文件中的宏定义。例如:

(举例多取自OGRE源码,一般都标注了其文件名)

class _OgreExport ConfigFile :public ConfigAlloc //OgreConfigFile.h

class _OgreExport ArchiveManager : public Singleton<ArchiveManager>,public ArchiveAlloc  //OgreArchiveManager.h

而为了统一形式,在OgreMemoryAllocatorConfig.h头文件中为继承自AllocatedObject的类定义如下两个宏:

#define OGRE_NEWnew

#define OGRE_DELETEdelete

因此在使用时,形式如下

ArchiveManager* mArchiveManager = OGRE_NEW ArchiveManager();


使用内存操作宏

除了继承使用AllocatedObject类之外,对于C++中的原始类型(int, double等),或者来自外部库的不能更改的类型,或者某些原因而不能继承AllocatedObject的类型来说,如果要对它们使用Ogre自定义内存策略,则可以使用OgreMemoryAllocatorConfig.h头文件中定义的内存操作宏:

以下三个宏用于分配原始内存,只是分配相应大小的内存,并不进行初始化:

OGRE_MALLOC(bytes, category)

       -- 分配bytes大小的内存

OGRE_ALLOC_T(T, count,category)

       -- 分配sizeof(T) * count大小的内存

OGRE_FREE(ptr, category)

         -- 与上述两个配对使用,释放ptr指向的内存

以下四个宏分配相应内存并进行初始化:

OGRE_NEW_T(T, category)

        -- 分配sizeof(T)大小的内存,并调用T的构造函数

OGRE_NEW_ARRAY_T(T, count,category)

        -- 分配sizeof(T) * count大小的内存,并对count个T类型实例依次初始化

OGRE_DELETE_T(ptr, T,category)

        OGRE_NEW_T配对使用,调用T的析构函数,释放相应内存

OGRE_DELETE_ARRAY_T(ptr, T,count, category)

        --OGRE_NEW_ARRAY_T配对使用,对count个T类型实例依次调用其析构函数,释放相应内存

举例:

// OgreTexture.cpp

void* pixData = OGRE_MALLOC(dataSize,Ogre::MEMCATEGORY_GENERAL);

// OgreAxisAlignedBox.h

Vector3* mpCorners = OGRE_ALLOC_T(Vector3, 8,MEMCATEGORY_SCENE_CONTROL);

OGRE_FREE(mpCorners, MEMCATEGORY_SCENE_CONTROL);

// OgreAnimationState.cpp

BoneBlendMask* mBlendMask = OGRE_NEW_T(BoneBlendMask, MEMCATEGORY_ANIMATION)(blendMaskSizeHint);

OGRE_DELETE_T(mBlendMask, BoneBlendMask, MEMCATEGORY_ANIMATION);

// OgreBspLevel.cpp

Brush * mBrushes = OGRE_NEW_ARRAY_T(BspNode::Brush,mNumBrushes, MEMCATEGORY_GEOMETRY);

OGRE_DELETE_ARRAY_T(mBrushes, Brush, (size_t)mNumBrushes,MEMCATEGORY_GEOMETRY);

对于以上7个内存操作宏分别有与其对应的对齐方式的宏定义,如OGRE_MALLOC_SIMDOGRE_MALLOC_ALIGNOGRE_ALLOC_T_SIMDOGRE_NEW_T_ALIGNOGRE_DELETE_ARRAY_T_ALIGN 等等。

***使用这些宏时,如果类型T本身继承于AllocatedObject,对程序本身也不会产生什么坏的影响,除了显得多此一举。


Ogre提供的内存分配/释放跟踪器

Ogre自己提供的NedAllocPolicyNedAlignedAllocPolicy)、NedPoolingPolicyNedPoolingAlignedPolicy)、StdAllocPolicyStdAlignedAllocPolicy)三种内存分配策略中,都包含了分配/释放跟踪功能,如需在自定义的分配策略中添加跟踪功能,照搬即可。该功能由MemoryTracker类实现,它统计内存的分配和释放情况,以及内存分配语句所在文件名、行号和函数名。默认在程序结束时将统计信息输出到终端,并保存于OgreLeaks.log文件,也可通过成员函数setReportToStdOut(bool rep)setReportFileName(const std::string& name)设置输出方式。

跟踪器的使用方式都在分配策略中完成,无需在它处额外操作。唯一需要设置的就是跟踪器开关的打开与关闭

OgrePrerequisites.h文件中有如下宏定义

#if OGRE_DEBUG_MODE

#if OGRE_MEMORY_TRACKER_DEBUG_MODE

#define OGRE_MEMORY_TRACKER 1

#else

#define OGRE_MEMORY_TRACKER 0

#endif

#else

#if OGRE_MEMORY_TRACKER_RELEASE_MODE

#define OGRE_MEMORY_TRACKER 1

#else

#define OGRE_MEMORY_TRACKER 0

#endif

#endif

即,OGRE_MEMORY_TRACKER宏开关取决于OGRE_MEMORY_TRACKER_DEBUG_MODEOGRE_MEMORY_TRACKER_RELEASE_MODE。而在OgreBuildSettings.h中定义有

#define OGRE_MEMORY_TRACKER_DEBUG_MODE 0

#define OGRE_MEMORY_TRACKER_RELEASE_MODE 0

即默认是关闭跟踪器的,如果需要在DEBUG版下打开跟踪器,只需要将OGRE_MEMORY_TRACKER_DEBUG_MODE设置为1。而根据OgreMemoryAllocatorConfig.h文件中内存操作宏的设置():

#if OGRE_DEBUG_MODE    //语句1

//详见源文件

#else // !OGRE_DEBUG_MODE

#endif // OGRE_DEBUG_MODE

即便是打开了OGRE_MEMORY_TRACKER_RELEASE_MODE宏,跟踪器也不能记录内存分配语句所在文件名、行号和函数名,即不能正常工作。如果需要在Release版下正常开启跟踪器功能,建议将语句1#if OGRE_DEBUG_MODE”改为“#if OGRE_MEMORY_TRACKER”。


举例:

对于如下代码

#include <string>

#include <OgreRoot.h>

#include <OgreMemoryAllocatorConfig.h>

#include <OgreArchiveManager.h>

using std::string;

int main()

{

{

    int *pi =OGRE_NEW_T(int, Ogre::MEMCATEGORY_GENERAL)(50);

    OGRE_FREE(pi,Ogre::MEMCATEGORY_GENERAL); //释放

    double *pd =OGRE_NEW_ARRAY_T(double, 5, Ogre::MEMCATEGORY_GENERAL);

    OGRE_FREE(pd,Ogre::MEMCATEGORY_GENERAL); //释放

    string *psOGRE_NEW_T(string, Ogre::MEMCATEGORY_GENERAL)("hello");

    OGRE_DELETE_T(ps,string, Ogre::MEMCATEGORY_GENERAL); //释放

}

{

    Ogre::ArchiveManager*mArchiveManager = OGRE_NEW Ogre::ArchiveManager();

    OGRE_DELETE mArchiveManager; //释放

}

return 0;

}

现开启跟踪器宏开关,即将OGRE_MEMORY_TRACKER_DEBUG_MODEOGRE_MEMORY_TRACKER_RELEASE_MODE 都置为1(须重新编译)。该代码正确释放了所有内存,不存在内存泄漏。如果将代码中释放内存的语句全部注释掉,则在Debug版下生成的OgreLeaks.log文件的内容为:

Ogre Memory: Detected memory leaks !!!

Ogre Memory: (6) Allocation(s) with total 244 bytes.

Ogre Memory: Dumping allocations ->

e:\vs project\ogretest\testmain.cpp(12) : {4 bytes} function: main

e:\vs project\ogretest\testmain.cpp(15) : {40 bytes} function: main

e:\vs project\ogretest\testmain.cpp(25) : {64 bytes} function: main

(unknown source):(0) : {52 bytes} function:

(unknown source):(0) : {52 bytes} function:

e:\vs project\ogretest\testmain.cpp(18) : {32 bytes} function: main

在Release版下生成的OgreLeaks.log文件的内容为:

Ogre Memory: Detected memory leaks !!!

Ogre Memory: (8) Allocation(s) with total 248 bytes.

Ogre Memory: Dumping allocations ->

(unknown source):(0) : {48 bytes} function:

(unknown source):(0) : {28 bytes} function:

(unknown source):(0) : {4 bytes} function:

(unknown source):(0) : {4 bytes} function:

(unknown source):(0) : {4 bytes} function:

(unknown source):(0) : {72 bytes} function:

(unknown source):(0) : {40 bytes} function:

(unknown source):(0) : {48 bytes} function:

可以看出在Debug版下,跟踪器正常工作,顺利的检测出全部四处内存泄漏,而在Release版下则不能正常工作。将#if OGRE_DEBUG_MODE”改为“#if OGRE_MEMORY_TRACKER”后,重新在Release版下测试,跟踪器便能正常工作,生成的OgreLeaks.log的内容为:

Ogre Memory: Detected memory leaks !!!

Ogre Memory: (8) Allocation(s) with total 248 bytes.

Ogre Memory: Dumping allocations ->

(unknown source):(0) : {48 bytes} function:

.\TestMain.cpp(18) : {28 bytes} function: main

.\TestMain.cpp(12) : {4 bytes} function: main

(unknown source):(0) : {4 bytes} function:

(unknown source):(0) : {4 bytes} function:

.\TestMain.cpp(25) : {72 bytes} function: main

.\TestMain.cpp(15) : {40 bytes} function: main

(unknown source):(0) : {48 bytes} function:


P.S.

1. 测试代码中,对int和double类型使用的是OGRE_NEW_TOGRE_FREE 来分别分配和释放内存,而并非前文所说的OGRE_DELETE_T,原因是因为对于int,double等基本类型来说,是没有析构函数的,而OGRE_DELETE_T宏是要调用相应析构函数的。

2. 测试代码中,若将using std::string;注释掉,并将相应string类型测试语句换为如下两句:

std::string *ps2 =OGRE_NEW_T(std::string,Ogre::MEMCATEGORY_GENERAL)("world");

OGRE_DELETE_T(ps2, basic_string,Ogre::MEMCATEGORY_GENERAL);

其中basic_string 不能是string 或 std::string !!!  同样是因为OGRE_DELETE_T宏要调用basic_string类的析构函数。类似情况还有在使用std::fostream,std::fistream等等时。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 刚出生的孩子不吃母乳怎么办 月子里挤奶手痛怎么办 做完月子之后腿疼腰疼怎么办 腰疼引起的腿疼怎么办 上网上久了脑袋痛怎么办 莲花坐的脚麻怎么办 月子腿疼膝盖疼怎么办 做月子腿着凉了怎么办 出月子大腿根酸怎么办 出了月子腰酸痛怎么办 出了月子腿没劲怎么办 生完孩子后缺钙怎么办 生完孩子腿疼怎么办 生完孩子后腿疼怎么办 生完孩子肛门突出怎么办 生完孩子肋骨突出怎么办 蛙跳理蛙跳后腿疼怎么办 蛙跳两天后腿还疼怎么办 莲花菩提盘黑了怎么办 体育课蛙跳后肌肉拉伤怎么办 o型腿骨头弯了怎么办 小孩钢琴坐姿不对向后仰怎么办 小孩皮肤不好容易留疤怎么办 学游泳时站不稳怎么办 水呛到了不停打嗝怎么办 来月经前游泳了怎么办 快来完事游泳了怎么办 游泳时来月经了怎么办 经期第7天游泳了怎么办 来月经已经游了泳怎么办 月经来了要游泳怎么办 三个月宝宝趴着不会抬头怎么办 我的月经不完怎么办 游泳时怎么办能浮出水面 游泳时眼镜起雾怎么办 练瑜伽手臂变粗怎么办 孕妇喝了芬达怎么办 宫口开了但头高怎么办 整天坐着肚子越来越大怎么办 坐久了屁股变大怎么办 屁股久坐的黑印怎么办