原文:OGRE 内存管理

Ogre引擎中与内存管理相关的文件大致有以下几个(只列出头文件)

OgreAlignedAllocator.h

OgreMemoryAllocatedObject.h

OgreMemoryAllocatorConfig.h

OgreMemoryNedAlloc.h

OgreMemoryNedPooling.h

OgreMemoryStdAlloc.h

OgreMemorySTLAllocator.h

OgreMemoryTracker.h

Ogre引擎的内存分配方式主要有三种:NEDPOOLING、NED、STD,通过定义宏OGRE_MEMORY_ALLOCATOR来进行选择,默认情况下使用的是NEDPOOLING。

Ogre中所有的分配方式都分为对齐分配内存与不对齐两种class,取名方式是XXAlignedPolicy与XXAllocPolicy,并且所有的内存函数都是静态(static)的。真正做分配功能的函数名字固定为以下四个:

  1. static void*
    allocBytes(size_t count,
  2. const char*
    file, int line, const char*
    func);
  3. static void deallocBytes(void*
    ptr);
  4. static void*
    allocBytesAligned(size_t align, size_t count,
  5. const char*
    file, int line, const char*
    func);
  6. static void deallocBytesAligned(size_t align, void*
    ptr);

实质上每种分配方式最主要的功能就是实现这四个函数,至于为什么要统一固定这四个函数的名字,看到最后就会明白~

(1)STD,对应头文件OgreMemoryStdAlloc.h / OgreAlignedAllocator.h

对齐分配类名:template <size_t Alignment = 0> class StdAlignedAllocPolicy

不考虑对齐类名:class StdAllocPolicy

这类方式顾名思义,也就是使用最直接的malloc/free方式进行内存分配和释放。这里可以关注下的是StdAlignedAllocPolicy模板类。

StdAlignedAllocPolicy模板类使用Alignment作为模板参数,该参数的意思是内存对齐的字节数,默认参数为0。当使用默认参数0时,Ogre会自动使用OGRE_SIMD_ALIGNMENT宏来进行对齐,该宏默认值是16。

在这个类中,还应用一种元模板技术,代码片段如下:

  1. template <size_t Alignment
    = 0>
  2. class StdAlignedAllocPolicy
  3. {
  4. public:
  5. // compile-time check alignment is available.
  6. typedef int IsValidAlignment
  7. [Alignment <= 128 && ((Alignment & (Alignment-1)) == 0) ? +1 : -1];
  8. ...
  9. };

其实这并不神秘,如上代码中使用到的元模板技术可以简单地理解为是一种在编译时做模板参数的正确性检查的方法。

就这段代码而言,这里typedef定义IsValidAlignment数组的作用,是利用数组长度不能为负的编译报错形式,检查Alignment参数的有效性。如果Alignment满足小于等于128并且是2的次方数,数组长度为1,编译正确;反之编译时报错。这样就在编译时规定了Alignment参数的数字形式,不会将问题留到运行时。

还有一个值得说的就是对齐分配的算法

在StdAlignedAllocPolicy模板类中是调用了另一个类AlignedMemory的静态函数来完成这一功能的。下面就来看下AlignedMemory类的分配和释放函数的原貌吧。

(i)分配函数

  1. void*
    AlignedMemory::allocate(size_t size, size_t alignment)
  2. {
  3. assert(0 < alignment && alignment <= 128 && Bitwise::isPO2(alignment));
  4. unsigned char*
    p = new unsigned char[size
    + alignment];
  5. size_t offset
    = alignment - (size_t(p)
    & (alignment-1));
  6. unsigned char*
    result = p + offset;
  7. result[-1] = (unsigned char)offset;
  8. return result;
  9. }

乍一看没明白?没关系,先给出Ogre代码中的注释

  1. /**
  2. *
  3. * |___2___|3|_________5__________|__6__|
  4. * ^ ^
  5. * 1 4
  6. *
  7. * 1 -> Pointer to start of the block allocated by new.
  8. * 2 -> Gap used to get 4 aligned on given alignment
  9. * 3 -> Byte offset between 1 and 4
  10. * 4 -> Pointer to the start of data block.
  11. * 5 -> Data block.
  12. * 6 -> Wasted memory at rear of data block.
  13. */

图中1所指向的就是new出的内存首地址,就是分配函数中p指针的指向之地。

图中2与3是一段内存,名为offset,是通过计算得到的,计算的算式就是

  1. size_t offset
    = alignment - (size_t(p) & (alignment-1));

假设alignment是4,size_t(p)是将p的地址转换为无符号的十进制数,然后位操作是取这个十进制数的二进制形式的最后4位。

这里应该是个数学问题,如果是4的话,这样位操作的结果是余数,至于其他2的次方数不知道是不是也是这样。最后相减后的offset值就是本次内存分配需要调整的字节长度。

通过p+offset的操作得到最后的真正存放数据的地址,就是注释图中4的位置。

最后的一行代码将result[-1]存放offset值的作用,是为了在释放时正确算回p的位置,一会儿就能在代码中看到。

(ii)释放函数

  1. void AlignedMemory::deallocate(void*
    p)
  2. {
  3. if (p)
  4. {
  5. unsigned char*
    mem = (unsigned char*)p;
  6. mem = mem - mem[-1];
  7. delete []
    mem;
  8. }
  9. }

有了分配函数中的解释,再看这个函数是不是就很简单了。

(2)NED,对应头文件OgreMemoryNedAlloc.h

nedmalloc 是一个可选的malloc内存分配的实现,主要是适应多线程无锁操作。主页是http://www.nedprod.com/index.html

了解了STD的操作方式后,再来看NED就简单很多了,类的结构也基本一致。

对齐分配类名:template <size_t Alignment = 0> class NedAlignedAllocPolicy

不考虑对齐类名:class NedAllocPolicy

NedAllocImpl类封装了所有内存分配函数,相当于STD中AlignedMemory的地位,这种调用方式有点类似设计模式中的Bridge,将抽象与实现部分进行了分离。

由于Nedmalloc中都已经有相应的对齐分配的api,所以在这种分配方式下直接调用就可以了。

(3) NEDPOOLING, 对应头文件OgreMemoryNedPooling.h

Ogre默认的分配方式,拥有与NED基本一致的类结构

对齐分配类名:template <size_t Alignment = 0> class NedPoolingAlignedPolicy

不考虑对齐类名:class NedPoolingPolicy

实现类名:class NedPoolingImpl

顾名思义,这种分配方式就是ned基础上使用内存池技术,ned自带有内存池的api,所以代码部分看起来也不会太难。

这里可以关注的是NedPoolingImpl中的函数,这些函数都是在_NedPoolingIntern namespace中的全局函数,也就是说_NedPoolingIntern 命名空间中的函数才是真正调用ned的代码。

    1. namespace _NedPoolingIntern
    2. {
    3. const size_t s_poolCount
      = 14; // Needs to be greater than 4
    4. void*
      s_poolFootprint = reinterpret_cast<void*>(0xBB1AA45A);
    5. nedalloc::nedpool* s_pools[s_poolCount + 1] = { 0 };
    6. nedalloc::nedpool* s_poolsAligned[s_poolCount + 1] = { 0 };
    7. size_t poolIDFromSize(size_t a_reqSize);

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

  1. 【转载】ogre内存管理

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

  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. 为centos添加额外的源

    使用这个命令: yum install epel-release

  2. 请求在Struts2框架中的处理步骤

    上图来源于Struts2官方站点,是Struts 2 的整体结构. 一个请求在Struts2框架中的处理大概分为以下几个步骤 1 客户端初始化一个指向Servlet容器(例如Tomcat)的请求 2 ...

  3. 【python cookbook】【数据结构与算法】15.根据字段将记录分组

    问题:想根据字典或者对象实例的某个特定的字典(比如日期)来分组迭代数据 解决方案:itertools.groupby()函数在对数据进行分组时特别有用(前提是先以目标字典进行排序) rows = [ ...

  4. Asp.Net Web Api 2 实现多文件打包并下载文件示例源码_转

    一篇关于Asp.Net Web Api下载文件的文章,之前我也写过类似的文章,请见:<ASP.NET(C#) Web Api通过文件流下载文件到本地实例>本文以这篇文章的基础,提供了Byt ...

  5. Python包管理工具介绍

    常见的包管理工具及关系 setuptools -->distribute easy_install-->pip 1.distribute distribute是对标准库disutils模块 ...

  6. HDU 5794:A Simple Chess(Lucas + DP)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5794 题意:让一个棋子从(1,1)走到(n,m),要求像马一样走日字型并只能往右下角走.里 ...

  7. 直接在Chrome里抓取数据

    一个小测试发现可以自动做题,于是想通过脚本的方式看能不能获取相应的题库,刚好可以学习一下JS异步操作.花了一天时间,总算跑顺利了,遇到了不少坑.记录下来分享. 1.JS如何顺序执行 JS有强大的异步操 ...

  8. 流量分析 seo alexa 排名

    百度权重 举例,百度搜索中输入"中医百科" ,排名前三的: http://www.a-hospital.com/w/中医 1. url是关键词的方式,包含中文名,说明当前百度的搜索 ...

  9. java 编程时候的性能调优

    一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...

  10. ACM题目————中缀表达式转后缀

    题目描述 我们熟悉的表达式如a+b.a+b*(c+d)等都属于中缀表达式.中缀表达式就是(对于双目运算符来说)操作符在两个操作数中间:num1 operand num2.同理,后缀表达式就是操作符在两 ...