原文:ogre内存管理

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

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

OgreMemoryAllocatedObject.h  OgreMemoryAllocatedObject.cpp

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

OgreMemoryAllocatorConfig.h

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

OgreMemoryNedAlloc.h  OgreMemoryNedAlloc.cpp

// 使用nedalloc库,定义了类NedAllocPolicy、NedAlignedAllocPolicy

OgreMemoryNedPooling.h  OgreMemoryNedPooling.cpp

// 使用nedalloc库,定义了类NedPoolingPolicy、NedPoolingAlignedPolicy

OgreMemoryStdAlloc.h

// 定义了类StdAllocPolicy、StdAlignedAllocPolicy

// 只是对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 typename std::vector<T, A> type;

#else

typedef typename std::vector<T> type;

#endif

};

如上所示,OGRE对STL容器进行了简单的包装,使其默认使用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提供了如下三种内存策略:

NedAllocPolicy(NedAlignedAllocPolicy)

NedPoolingPolicy(NedPoolingAlignedPolicy)

StdAllocPolicy(StdAlignedAllocPolicy)

在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_CUSTOM 5

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

#elif OGRE_MEMORY_ALLOCATOR == OGRE_MEMORY_ALLOCATOR_CUSTOM

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

namespace Ogre

{

template <MemoryCategory Cat> class CategorisedAllocPolicy : public CustomAllocPolicy{};

template <MemoryCategory Cat, size_t align = 0> class CategorisedAlignAllocPolicy : public CustomAlignAllocPolicy<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_NEW new

#define OGRE_DELETE delete

因此在使用时,形式如下

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_SIMD、OGRE_MALLOC_ALIGN、OGRE_ALLOC_T_SIMD、OGRE_NEW_T_ALIGN、OGRE_DELETE_ARRAY_T_ALIGN 等等。

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

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

在Ogre自己提供的NedAllocPolicy(NedAlignedAllocPolicy)、NedPoolingPolicy(NedPoolingAlignedPolicy)、StdAllocPolicy(StdAlignedAllocPolicy)三种内存分配策略中,都包含了分配/释放跟踪功能,如需在自定义的分配策略中添加跟踪功能,照搬即可。该功能由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_MODE 或OGRE_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 *ps =  OGRE_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_MODE 和 OGRE_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_T 和 OGRE_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等等时。

 
 

【转载】ogre内存管理的更多相关文章

  1. 【转载】OGRE 内存管理

    原文:OGRE 内存管理 Ogre引擎中与内存管理相关的文件大致有以下几个(只列出头文件) OgreAlignedAllocator.h OgreMemoryAllocatedObject.h Ogr ...

  2. [转载]C++内存管理

    [导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不 ...

  3. [转载] Linux内存管理之mmap详解

    转载自http://blog.chinaunix.net/uid-26669729-id-3077015.html 一. mmap系统调用 1. mmap系统调用 mmap将一个文件或者其它对象映射进 ...

  4. 转:内存区划分、内存分配、常量存储区、堆、栈、自由存储区、全局区[C++][内存管理][转载]

    内存区划分.内存分配.常量存储区.堆.栈.自由存储区.全局区[C++][内存管理][转载] 一. 在c中分为这几个存储区1.栈 - 由编译器自动分配释放2.堆 - 一般由程序员分配释放,若程序员不释放 ...

  5. Apache Spark 内存管理详解(转载)

    Spark 作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色.理解 Spark 内存管理的基本原理,有助于更好地开发 Spark 应用程序和进行性能调优.本文旨在梳理出 ...

  6. iOS 内存管理(转载)

     N久没维护这个博客了,从开始接触编程到现在已经三四年了.不太习惯写博客,这应该是个不好的习惯.所以从哪哪天开始,我得改变自己 (:       . 文采不太好,因此很多的文章都会借鉴他人的,但是我一 ...

  7. 【转载】浅谈Linux内存管理机制

    经常遇到一些刚接触Linux的新手会问内存占用怎么那么多? 在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在 ...

  8. [转载]Java应用程序中的内存泄漏及内存管理

    近期发现测试的项目中有JAVA内存泄露的现象.虽然JAVA有垃圾回收的机制,但是如果不及时释放引用就会发生内存泄露现象.在实际工作中我们使用Jprofiler调用java自带的 jmap来做检测还是很 ...

  9. <转载>内存管理内幕-动态分配的选择、折衷和实现 对malloc内存分配有个简单的描述,对内存管理有个大致的说明

    这篇文章看后感觉不错,和我在glibc下的hurdmalloc.c文件里关于malloc的实现基本意思相同,同时,这篇文章还介绍了一些内存管理方面的知识,值得推荐. 原文链接地址为:http://ww ...

随机推荐

  1. zw版【转发·台湾nvp系列Delphi例程】HALCON HWindow Overlayer 1

    zw版[转发·台湾nvp系列Delphi例程]HALCON HWindow Overlayer 1 ------------------------------------HALCON HWindow ...

  2. css在IE和Firefox下的兼容性

    1.div的垂直居中问题 vertical-align:middle,将行距增加到和整个div高度一样,加line-height:200px;然后插入文字就垂直居中了.缺点是要控制内容不要换行. 2. ...

  3. ubuntu遇到的命令

    sudo passwd root这个命令是给root用户设定密码.su root切换到root用户.sudo cp 文件 /var/www移动文件到一个目录unzip xxx.zip解压zip文件mk ...

  4. Asp.Net MVC 模型验证详解-实现客户端、服务端双重验证

    概要 在asp.net webform开发中经常会对用户提交输入的信息进行校验,一般为了安全起见大家都会在客户端进行Javascript(利于交互).服务端双重校验(安全).书写校验代码是一个繁琐的过 ...

  5. JSP直接连接sql2008数据库并显示

    <%@ page contentType="text/html; charset=utf-8" language="java" errorPage=&qu ...

  6. javaWeb 使用jsp标签进行防盗链

    /** * 1.新建类继承SimpleTagSupport * 新建2个属性, 添加对应的set方法 * 覆盖doTag()方法 */ import java.io.IOException; impo ...

  7. ASP+Access UTF-8 网页乱码问题解决办法

    用ACCESS数据库和ASP做网站时用UTF-8编码有时会出现乱码,再者网页出错或者刷新页面后就是乱码,如果数据库取值乱码在开头加上<%@LANGUAGE="VBSCRIPT" ...

  8. 如何在ecshop商品详情页显示供货商信息

    以下范例以ecshop2.7.2原型做为修改: 1.首先需要修改程序文件,将供货商读取出来,然后赋值给模板,   打开文件 /goos.php,   在                   $smar ...

  9. vscode使用php调试

    1:首先查看是否安装xdebug扩展 打开终端  ➜ ~ php -vPHP 5.6.24 (cli) (built: Jul 21 2016 14:27:54) Copyright (c) 1997 ...

  10. MyBatis 判断条件为等于的问题

    在用MyBatis操作数据库的时候相信很多人都用到,当在判断null, 大于,大于等于,小于,小于等于,不等于时估计很多都用到,比较容易实现了,这里就省略了,但唯独判断条件为等于时估计蛮多人遇到坑了, ...