原文: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. Report launcher to run SSRS report subscriptions on demand

    http://www.mssqltips.com/sqlservertip/3078/report-launcher-to-run-ssrs-report-subscriptions-on-deman ...

  2. 查看innodb表空间

    使用脚本innodb_space,关于innodb的页管理方式可以参考Jeremy Cole的innodb的页管理方式, innodb_space -f test/t.ibd space-page-t ...

  3. java中的单例设计模式

    单例模式有一下特点: 1.单例类只能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供 ...

  4. Temporary InMemory Tables [AX 2012]

    Temporary InMemory Tables [AX 2012] This topic has not yet been rated - Rate this topic Updated: Oct ...

  5. unicode转码,如:\u6d4b\u8bd5转成中文“测试”

    public static void main(String[] args) { String s = "测试"; String tt = gbEncoding(s); // St ...

  6. iOS开发 爱特开发技术bug总结

    #pragma mark 每天总结学习两小时  效率 和 每天学习 研究底层 多进去看看 // .................................................... ...

  7. Codefroces Gym 100781A(树上最长路径)

    http://codeforces.com/gym/100781/attachments 题意:有N个点,M条边,问对两两之间的树添加一条边之后,让整棵大树最远的点对之间的距离最近,问这个最近距离是多 ...

  8. node-webkit教程<>Native UI API 之Menu(菜单)

    node-webkit教程(6)Native UI API 之Menu(菜单)1 前言... 2 6.1  Menu 概述... 3 6.2  menu api6 6.2.1  new Menu([o ...

  9. Asp.net Vnext api CORS( 跨域)

    概述 跨域资源共享(CORS )是一种网络浏览器的技术规范,它为Web服务器定义了一种方式,允许网页从不同的域访问其资源.而这种访问是被同源策略所禁止的.CORS系统定义了一种浏览器和服务器交互的方式 ...

  10. redis初试牛刀

    先来无事就学学redis.可是并没有想的那么美好.首先要解释一下,redis主流是安装在lunx系统中的,甚至官网直接没有给出windows版本.要下载windows只能去所谓的githup.好吧我在 ...