Memory Management in Open Cascade
Open Cascade中的内存管理
Memory Management in Open Cascade
一、C++中的内存管理 Memory Management in C++
1. 引言
为了表现出多态,在C++中就会用到大量的指针和引用。指针所指的对象是从内存空间中借来的,当然要及时归还。特别是指针在程序中随心所欲地创建,因此,一个指针究竟指向哪个对象,一个对象到底被几个指针所指向,是程序员十分关注的事情。
C++中涉及到的内存管理问题可以归结为两方面:正确地掌握它和有效地使用它。好的程序员会理解这两个问题为什么要以这样的顺序列出。因为执行得再快、体积再小的程序,如果不按所期望的方式去执行也是没什么用处的程序。对于大多数程序员,正确地掌握意味着正确地调用内存分配和释放函数;有效地使用意味着编写自定义版本的内存分配和释放函数。显然,正确地掌握它要重要些。
在C中,只要用malloc分配的内存没有用free释放就会产生内存泄露。在C++中肇事者的名字换成了new和delete,但是问题依然存在。当然,有了析构函数情况稍有改观。因为析构函数为所有将被销毁的对象提供了一个方便的调用delete的场所,但这同时又带来了更多的烦恼,因为new和delete是隐式地调用构造函数和析构函数的。而且可以在类中和类外自定义new和delete操作符,这又带来了复杂性,增加出错的机会。
2. 内存分配方式
内存分配有三种方式:
u 从静态存储区域分配。内存在编译时就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量、static变量;
u 从栈上分配。在执行函数时,函数内的局部变量的存储单元都能在栈上创建,函数执行结束时,这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配内存容量有限;
u 从堆上分配,亦称动态内存分配。程序在运行时用malloc或new申请任意多少的内存,程序员自己负责在用完时使用free或delete来释放内存。动态内存的生存期由我们决定,使用起来很灵活,但问题也最多。
二、Open Cascade中的内存管理 Memory Management in Open Cascade
在几何建模的过程中,程序创建和删除了大量的对象在动态内存中,也就是堆中。在这种情况下,标准C++的内存管理方式不是很高效,所以Open Cascade在包Standard中专门写了个内存管理程序(Memory Manager)来对内存的分配与删除进行管理。
1. 用法 Usage
为了在C代码中使用Open Cascade提供的内存管理器,只需要将原来使用malloc的地方使用Standard::Allocate来代替,原来使用free的地方使用Standard::Free来代替。另外,原来使用realloc的地方使用Standard::Reallocate来代替即可。
在C++中,operator new 和 delete都重新定义以便使用Open Cascade的内存管理器。定义代码如下所示:
public:
// Redefined operators new and delete ensure that handles are
// allocated using OCC memory manager
void* operator new(size_t,void* anAddress)
{
return anAddress;
} void* operator new(size_t size)
{
return Standard::Allocate(size);
} void operator delete(void *anAddress, size_t )
{
if (anAddress) Standard::Free(anAddress);
}
上述代码是将operator new和delete及placement new都重新定义了,这样的类的new和delete都将由Open Cascade的内存管理器来管理。
CDL extractor为在其中所有类都采用这种方式来重新定义operator new和delete,这样Open Cascade所有的类(少数除外)都是使用Open Cascade的内存管理器来管理。
2. 配置内存管理器 Configuring memory manager
Open CASCADE内存管理器可以配置,按不同的优化方式来分配内存,主要还是看需要分配内存的大小,或者不使用内存优化而直接使用malloc和free。
配置方式为设置如下环境变量的值:
l MMGT_OPT:若设置为1(默认值也是为1),内存管理器将使用内存优化的方式来管理内存;若设置为0,则内存的分配就是直接调用C的函数malloc和free来对内存进行管理,此时,所有其它选项除了MMGT_CLEAR外都将被忽略。若设置为2,则会使用Intel的TBB来对内存的分配进行优化,此时需要有TBB的库。
l MMGT_CLEAR:若设置为1(默认值也是为1),分配的内存块将被清零;若设置为0,则内存块将以分配时的值返回。
l MMGT_CELLSIZE:定义了内存池中可分配内存块的最大值。默认值为200。
l MMGT_NBPAGES:定义了页面上可分配的小的内存块的数量,默认值为1000。
l MMGT_THRESHOLD:定义了循环利用的而不是返回给堆的内存块的数量,默认值为4000。
l MMGT_MMAP:若设置为1(默认值也是为1),大内存块的分配将会使用操作系统的内存映射函数。若设置为0,内存的分配将会直接使用malloc直接在堆上分配。
l MMGT_REENTRANT:若设置为1(默认值为0),所有调用内存优化的函数将会被保证安全,即使有多个不同的线程。当在使用内存优化管理(MMGT_OPT=1)内存及多线程的程序时,这个值需要设置为1。
注:为了使用Open Cascade在多线程的程序中表现出更好的性能,推荐如下两种设置方式:
l MMGT_OPT=0
l MMGT_OPT=1 and MMGT_REENTRANT=1
3. 程序实现 Implementation details
类Standard_MMgrRoot为内存管理器的抽象类,它定义了内存分配的释放的虚函数。通过环境变量MMGT_OPT来选择不同的内存管理类,如下代码所示:
Standard_MMgrFactory::Standard_MMgrFactory() : myFMMgr()
{
char *var;
Standard_Boolean bClear, bMMap, bReentrant;
Standard_Integer aCellSize, aNbPages, aThreshold, bOptAlloc; //
bOptAlloc = atoi((var = getenv("MMGT_OPT" )) ? var : "" );
bClear = atoi((var = getenv("MMGT_CLEAR" )) ? var : "" );
bMMap = atoi((var = getenv("MMGT_MMAP" )) ? var : "" );
aCellSize = atoi((var = getenv("MMGT_CELLSIZE" )) ? var : "" );
aNbPages = atoi((var = getenv("MMGT_NBPAGES" )) ? var : "" );
aThreshold = atoi((var = getenv("MMGT_THRESHOLD")) ? var : "");
bReentrant = atoi((var = getenv("MMGT_REENTRANT")) ? var : "" ); if ( bOptAlloc == ) {
myFMMgr = new Standard_MMgrOpt(bClear, bMMap, aCellSize, aNbPages, aThreshold, bReentrant); } else if ( bOptAlloc == ) {
myFMMgr = new Standard_MMgrTBBalloc(bClear);
}
else {
myFMMgr = new Standard_MMgrRaw(bClear);
} // Set grobal reentrant flag according to MMGT_REENTRANT environment variable
if ( ! Standard_IsReentrant )
Standard_IsReentrant = bReentrant;
}
当MMGT_OPT设置为1时,将会使用类Standard_MMgrOpt来对内存的分配与释放进行优化。优化方法如下:
l 小型内存块(小于MMGT_CELLSIZE的内存)不是单独分配。而是分配一个大的内存池(每个内存池的大小是MMGT_NBPAGES),每个新建内存都被安排在当前的内存池中空闲的地方。若当前内存池被占满,则分配另一个内存池。在当前的版本中,内存池不会返回给系统(直到程序结束)。然而,调用函数Standard::Free()被释放的内存块会被free列表记录,以便在下一个相同大小的内存块分配时重新利用(循环使用)。
l 中型内存块(大小在MMGT_CELLSIZE和MMGT_THRESHOLD之间的内存块)由C的函数malloc和free直接管理。当这样的内存块被调用函数Standard::Free释放时,它们也像小型内存块那样被循环使用。与小型内存块不同的是,被释放的free列表中包含的中型内存块可以通过函数Standard::Purge,使其返回到堆中。
l 大型内存块(大于MMGT_THRESHOLD的内存块,包含用于管理小型内存块的内存池)的分配取决于MMGT_MMAP的值:若为0,这些内存块在堆中分配;否则,将会使用操作系统的专用的管理内存映射文件的函数来分配。当使用Standard::Free来释放大型内存块时,大型内存块立即返回给系统。
4. 利与弊 Benefits and drawbacks
Open Cascade使用内存管理器的最大好处就是其对小型内存块的循环使用机制。当程序需要对大量小型内存块进行分配与释放时,这种机制使程序速度更快。实践表明,使用这种方式程序的性能可以提高50%以上。
相应的弊端就是循环使的内存在程序运行时不会返回给系统。这就可能导致大量的内存消耗,甚至可能导致内存泄露。为了避免这种情况,应该在大量使内存的操作结束后调用函数Standard::Purge。
使用Open Cascade的内存管理器(Memory Manager)导致的所有的内存开销有:
l 分配的每个内存块的大小都会以8个字节向上取整。(看其源代码应该是以的个字节向上取整,源程序如下所示:)
Standard_Address Standard_MMgrRaw::Allocate(const Standard_Size aSize)
{
// the size is rounded up to 4 since some OCC classes
// (e.g. TCollection_AsciiString) assume memory to be double word-aligned
const Standard_Size aRoundSize = (aSize + ) & ~0x3;
// we use ?: operator instead of if() since it is faster :-)
Standard_Address aPtr = ( myClear ? calloc(aRoundSize, sizeof(char)) : malloc(aRoundSize) ); if ( ! aPtr )
Standard_OutOfMemory::Raise("Standard_MMgrRaw::Allocate(): malloc failed");
return aPtr;
}
l 额外的4个字节(在64位的操作系统上是8个字节)将在每个内存块的开始部分分配,用来保存其大小(或用来保存下一个可用的内存块的地址),只在MMGT_OPT为1时有效。
所以不管Open Cascade的内存管理器以优化方式还是标准方式来管理内存,内存总的消耗都将会大一些。
PDF Version: Memory Management in Open Cascade
Memory Management in Open Cascade的更多相关文章
- Java (JVM) Memory Model – Memory Management in Java
原文地址:http://www.journaldev.com/2856/java-jvm-memory-model-memory-management-in-java Understanding JV ...
- Objective-C Memory Management
Objective-C Memory Management Using Reference Counting 每一个从NSObject派生的对象都继承了对应的内存管理的行为.这些类的内部存在一个称为r ...
- Operating System Memory Management、Page Fault Exception、Cache Replacement Strategy Learning、LRU Algorithm
目录 . 引言 . 页表 . 结构化内存管理 . 物理内存的管理 . SLAB分配器 . 处理器高速缓存和TLB控制 . 内存管理的概念 . 内存覆盖与内存交换 . 内存连续分配管理方式 . 内存非连 ...
- Android内存管理(2)HUNTING YOUR LEAKS: MEMORY MANAGEMENT IN ANDROID PART 2
from: http://www.raizlabs.com/dev/2014/04/hunting-your-leaks-memory-management-in-android-part-2-of- ...
- Android内存管理(1)WRANGLING DALVIK: MEMORY MANAGEMENT IN ANDROID PART 1
from : http://www.raizlabs.com/dev/2014/03/wrangling-dalvik-memory-management-in-android-part-1-of-2 ...
- Understanding Memory Management(2)
Understanding Memory Management Memory management is the process of allocating new objects and remov ...
- Java Memory Management(1)
Java Memory Management, with its built-in garbage collection, is one of the language’s finest achiev ...
- ural1037 Memory Management
Memory Management Time limit: 2.0 secondMemory limit: 64 MB Background Don't you know that at school ...
- 再谈.net的堆和栈---.NET Memory Management Basics
.NET Memory Management Basics .NET memory management is designed so that the programmer is freed fro ...
随机推荐
- haahah
#DB ``` import os basedir = os.path.abspath(os.path.dirname(__file__)) SQLALCHEMY_DATABASE_URI = ' ...
- [BZOJ4200][Noi2015]小园丁与老司机
4200: [Noi2015]小园丁与老司机 Time Limit: 20 Sec Memory Limit: 512 MBSec Special JudgeSubmit: 106 Solved ...
- CodeForces 618A Slime Combining
http://www.codeforces.com/contest/618/problem/A 明明觉得是水题,而我却做了一个小时. 明明觉得代码没有错,而我却错了好几次. 因为我的名字不叫明明,也不 ...
- spring3.0使用annotation完全代替XML
@Service与@Component有什么不同?那天被问到这个问题,一时之间却想不起来,就利用这篇文章来纪录spring3.0中常用的annotation. 从spring2.5开始,annotat ...
- Torch7学习笔记(一)CmdLine
该类主要为了提供一种方便解析参数的框架,对于每个实验尤其是神经网络中要调参数上.同时还可以把输出重定向到log文件中. 一般用法: cmd = torch.CmdLine() cmd:text() c ...
- STM32之ADC+步骤小技巧(英文)
神通广大的各位互联网的网友们.大家早上中午晚上好好好.今早起来很准时的收到了两条10086的扣月租的信息.心痛不已.怀着这心情.又开始了STM32的研究.早上做了计算机控制的PID实验,又让我想起了飞 ...
- Python操作Mysql数据库时SQL语句的格式问题
一.概述 近日使用Python对Mysql数据库进行操作,遇到SQL语句死活出问题的情况.由于最初没有将异常打印出来,一直不知道原因.随后,将异常打印出来之后,通过异常信息,对代码进行修改.最终,成功 ...
- android之Handler机制
简单例子开头: 网络http请求网站源码数据并显示 注意点:访问网络需要加Internet权限: android.permission.INTERNET 简单的步骤: 使用UrlConnection请 ...
- java并发之volatile
volatile是轻量级的synchronized,它在多处理器应用开发中保证了共享变量的“可见性”(可见性指当一个线程修改共享变量后,其它线程可以看到这个修改). volatile如果使用合理会比s ...
- dev GridControl 根据鼠标坐标 选中行
if (e.Button == System.Windows.Forms.MouseButtons.Right) { DevExpress.XtraGrid.Views.Grid.ViewInfo.G ...