【转载】OGRE 内存管理

原文: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)的。真正做分配功能的函数名字固定为以下四个:

[cpp] view
plain
copy

  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。

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

[cpp] view
plain
copy

  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)分配函数

[cpp] view
plain
copy

  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代码中的注释

[cpp] view
plain
copy

  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,是通过计算得到的,计算的算式就是

[cpp] view
plain
copy

  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)释放函数

[cpp] view
plain
copy

  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的代码。

[cpp] view
plain
copy

    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);
时间: 2024-08-02 19:23:44

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

【转载】ogre内存管理

原文:ogre内存管理 OGRE内存分配策略相关文件及简述 OGRE提供了自己的内存分配策略,甚至为STL容器提供了新的分配策略,相关文件及简述如下: OgreMemoryAllocatedObject.h  OgreMemoryAllocatedObject.cpp // 所有使用Ogre内存分配器的类的父类 OgreMemoryAllocatorConfig.h // 配置内存分配相关规则 OgreMemoryNedAlloc.h  OgreMemoryNedAlloc.cpp // 使用n

[转载]C++内存管理

[导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不在,内存泄漏几乎在每个C++程序中都会发生,因此要想成为C++高手,内存管理一关是必须要过的,除非放弃C++,转到Java或者.NET,他们的内存管理基本是自动的,当然你也放弃了自由和对内存的支配权,还放弃了C++超绝的性能.本期专题将从内存管理.内存泄漏.内存回收这三个方面来探讨C++内存管理问题

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

转载自http://blog.chinaunix.net/uid-26669729-id-3077015.html 一. mmap系统调用 1. mmap系统调用 mmap将一个文件或者其它对象映射进内存.文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零.munmap执行相反的操作,删除特定地址区域的对象映射. 当使用mmap映射文件到进程后,就可以直接操作这段虚拟地址进行文件的读写等操作,不必再调用read,write等系统调用.但需注意,直接对该段内

[转载] python的内存管理机制

本文为转载,原作为http://www.cnblogs.com/CBDoctor/p/3781078.html,请大家支持原作者 先从较浅的层面来说,Python的内存管理机制可以从三个方面来讲 (1)垃圾回收 (2)引用计数 (3)内存池机制 一.垃圾回收: python不像C++,Java等语言一样,他们可以不用事先声明变量类型而直接对变量进行赋值.对Python语言来讲,对象的类型和内存都是在运行时确定的.这也是为什么我们称Python语言为动态类型的原因(这里我们把动态类型可以简单的归结

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

内存区划分.内存分配.常量存储区.堆.栈.自由存储区.全局区[C++][内存管理][转载] 一. 在c中分为这几个存储区1.栈 - 由编译器自动分配释放2.堆 - 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收3.全局区(静态区),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域.- 程序结束释放4.另外还有一个专门放常量的地方.- 程序结束释放                          

iOS性能优化之内存管理:Analyze、Leaks、Allocations的使用和案例代码 -[转载]

最近研究代码质量检测问题,在网上找的相关资料咱是如下: 一. 一些相关概念 很多人应该比较了解这块内容了...可以权当复习复习... 1.内存空间的划分: 我们知道,一个进程占用的内存空间,包含5种不同的数据区:(1)BSS段:通常是存放未初始化的全局变量:(2)数据段:通常是存放已初始化的全局变量.(3)代码段:通常是存放程序执行代码.(4)堆:通常是用于存放进程运行中被动态分配的内存段,OC对象(所有继承自NSObject的对象)就存放在堆里.(5)栈:由编译器自动分配释放,存放函数的参数值

OC内存管理(转载)

OC内存管理 一.基本原理 (一)为什么要进行内存管理. 由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等. 管理范围:任何继承NSObject的对象,对其他的基本数据类型无效. 本质原因是因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也

cocos2d-x内存管理机制解析(转载)

最近在看内存管理的源码,发现这篇文章讲的不错,思路很清晰,故转载收藏. 原地址:http://blog.csdn.net/a7833756/article/details/7628328 1.cocos2d-x 内存管理的方式,cocos2d-x采用引用计数的方式进行内存管理,当一个对象的引用计数为0的时候,就会被引擎自动delete掉. 所有cocos2d-x里面的类都继承ccobject类(应该是吧.),下面看ccobject类源码: 这里 m_uReference 就是引用计数,在对象构造

[转载]对iOS开发中内存管理的一点总结与理解

对iOS开发中内存管理的一点总结与理解 做iOS开发也已经有两年的时间,觉得有必要沉下心去整理一些东西了,特别是一些基础的东西,虽然现在有ARC这种东西,但是我一直也没有去用过,个人觉得对内存操作的理解是衡量一个程序员成熟与否的一个标准.好了,闲话不说,下面进入正题. 众所周知,ObjectiveC的内存管理引用的一种叫做“引用计数“ (Reference Count)的操作方式,简单的理解就是系统为每一个创建出来的对象,(这里要注意,只是对象,NSObject的子类,基本类型没有‘引用计数’)