Ogre

浏览量:920

OGRE内存分配策略

本文介绍了OGRE渲染引擎中的内存分配器,前言介绍了OGRE版本、编译环境、工具等信息,接着介绍了OGRE渲染引擎中的内存分配和策略的设计、实现。 一. 前言 分析的ogre源代码版本是 操作系统:windows 7 x64 编译工具:CMake 编译器:Visual Studio 2008 编译完成后会生成一个OgreBuildSettings.h文件,包括一些用户自定义的信息,举个简单的例子,下面的几个宏表示编译源码,使它支持D3D9渲染和OpenGL渲染功能,编译的插件有BSP、OCTREE、PCZ、PFX、CG,使用小端字节序。 #define OGRE_BUILD_RENDERSYSTEM_D3D9 /* #undef OGRE_BUILD_RENDERSYSTEM_D3D11 */ #define OGRE_BUILD_RENDERSYSTEM_GL /* #undef OGRE_BUILD_RENDERSYSTEM_GLES */ /* #undef OGRE_BUILD_RENDERSYSTEM_GLES2 */ #define OGRE_BUILD_PLUGIN_BSP #define OGRE_BUILD_PLUGIN_OCTREE #define OGRE_BUILD_PLUGIN_PCZ #define OGRE_BUILD_PLUGIN_PFX #define OGRE_BUILD_PLUGIN_CG OGRE的配置信息,包括分配器的选择、是否提供多线程支持、系统和编译器相关的一些宏定义等,一般保存在下面的几个头文件中。 OgreBuildSettings.h OgreConfig.h

spacer
浏览量:1,394

内存分配器浅谈

ogre渲染引擎中采用的是nedmalloc内存分配器,查了些资料,看了些论文,这里对ogre中使用的nedmalloc内存分配器进行简单的介绍。第1小节,介绍的是好的内存处理器的目标,第2小节,介绍dlmalloc分配器的基本思想,第3小节,介绍nedmalloc的性能。 一. 简介 参考【2】,作者总结了1995年以前的内存分配器,对内存分配器的目的、需要解决的问题、采用的策略等都进行了总结。其中要解决的一个很重要的问题就是碎片化(fragmentation),因为应用程序可以在任意时间,分配任意大小的对象,并在将来的某个时间释放这些内存,就可能导致一个结果就是:在两个使用的内存块之间存在非常小的空闲块,无法满足所要求的内存申请要求,也已经证实碎片化问题是无法避免。对碎片问题的研究在【2】都有详细的表述。 一个内存分配器主要的目的可以总结为如下几点: (1)最大化兼容性 与其它程序兼容,特别是它应该遵守ANSI/POSIX规范 (2)最大化可移植性 尽可能少的依赖系统相关的特征(比如系统调用),同时在某些系统上也要提供一些有用特征的可选操作。遵守系统对字节对齐规则和取址规则的约束。 (3)最小化时间 malloc()、free()和realloc()消耗的时间尽可能的少 (4)最大化可调性 一些可选的方法可以由用户来控制。有静态的(编译时)方法,使用(#define定义一些宏);有动态的(运行时)方法,使用命令来控制。 (5)最大化局部性 尽可能的分配物理内存相互接近的内存块,在程序执行时有利于最小化页面和cache的丢失。 (6)最大化错误检测 通用目的分配器也作为通用目的的内存错误检测工具,显得不太可能,但是分配器应该提供一些由于重写内存、多次释放等原因造成的内存崩溃。 (7)最小化异常 一个使用默认配置的分配器在不同的应用背景下,应该尽可能少的出现异常,比如在窗口工具包里、GUI应用中、编译器中、网络浏览器中等等。 一个内存分配器应当能记录使用的和空闲的内存,在合适的时间范围内最小化存储空间的浪费,即要做到时间开销和空间浪费之间的一个平衡。 二. dlmalloc算法基本思想 这里以dlmalloc内存分配器为例,参考【1】【3】,这里介绍它的算法基本思想。 2.1 边界标签 图1. 边界标签 在内存块的前面和后面都有大小信息,这能带来两个好处: (1)       两个相邻的空闲块能够合并成一个大的内存块 (2)       所有的内存块既能向前遍历,也能向后遍历。 2.2 装箱方法 图2. 装箱方法 内存块均以箱子的形式来维护,以箱子的大小来分组,有128个固定大小的箱子类型,小于512个字节的箱子之间的间隔大小是8个字节。对块的搜索采用最小优先、最佳优先的准则,以便减小碎片化的效果。在1995年以前的版本中,箱子中的块都没有进行排序,所以最佳优先的策略仅仅是一种估计。最近的实现版本中,箱子里的块不采用按大小排序,而是采用了最老优先的准则。 所以把这类算法的归类为“带合并的最佳优先算法”,相邻的空闲块合并为一个更大的空闲块,通过大小排序,把它保存在对应的箱子中。 通过边界标签完成合并和通过装箱方法完成最佳优先匹配,就是内存分配算法的主要思想。在此基础上完成一些启发式的改进,这些改进也是在实现中必需考虑到的一些因素,包括局部性的维护(Locality Preservation)、拓展块的维护(Wilderness Preservation)、内存映射(Memory Mapping)和高速缓存(Cache)。

spacer
浏览量:516

智能指针

示例代码:https://github.com/twinklingstar20/twinklingstar_cn_demo_ogre_smart_pointer 看到Ogre中的智能指针SharedPtr,于是结合以前在Webkit内核中看到的智能指针PassRefPtr和RefPtr一起进行介绍。 由于C++缺乏语言级别的GC(Garbage Collection)支持,实现的代码容易发生内存泄漏的BUG,但是GC也由于额外的负担,降低了代码的效率。另外一种朴素的方法就是智能指针,所谓的智能指针就是将一个计数器与指向的对象的指针相关联,引用计数跟踪该类有多少个对象共享同一指针,当引用计数达到一个阈值时,删除该对象。 对智能指针有深入的理解,前提必须对C++中复制构造函数、运算符重载、对象返回值的原理等有较深入的理解,这些概念的深入理解可以参考《Thinking in C++》这本书中第11章“References &the Copy-Constructor”小节的内容。这里就举一个简单的例子: #include <iostream> #include <vector> using namespace std; class TestCopyConstructor { public: TestCopyConstructor(string nm) { name = nm; } TestCopyConstructor& operator=(const TestCopyConstructor& s)//重载运算符 { this->name = s.name+"New"; printf("operator = : %s\n",name.c_str()); return

spacer