下面,图老师小编带您去了解一下C++引用计数的智能指针有效回收方法,生活就是不断的发现新事物,get新技能~
【 tulaoshi.com - 编程语言 】
引用计数指针是否能有效地回收,对系统意外关机之后数据的恢复来说至关重要,要害是要避免对象复制。 怎样从灾难性故障中,恢复一个长期运行、系统级的后台守护进程或者服务,在如今的软件设计过程中,已成为了一个重要的考虑因素。当这些软件是由C++语言编成,并使用了引用计数的智能指针时,那么,智能指针的有效回收,对系统是否具有可伸缩级的恢复能力、甚至正确地继续未完成的操作来说,都显得至关重要。 在本文中,描述了一种方法,可从关机之后的软件恢复中,有效地回收引用计数指针,而且此方法在内存占用方面也非常高效,这种方法的要害在于避免对象复制,而对象复制通常是由C++中指针引用的串行化与反串行化这种传统技术产生的。当从存档文件中反串行化时,本方法使用了标记(tag)来唯一地识别指针对象,且在系统恢复时由一个对象缓存来保存指针引用。 本文以一个基于事件的商业实时作业调度系统来进行演示,其通常由大型市场咨询公司使用,天天都会在集群工作站上处理数不胜数的计算任务。 为什么许多C++软件项目会使用自动内存治理技术呢,因为它有以下好处: ² 代码安全性。避免了太早释放一个对象所带来的风险。 ² 代码正确性。避免了忘记释放未使用内存所带来的风险。 ² 代码模块性。代码中不再需要点缀着与程序无关的簿记代码。 ² 编程简单性。现在可假定一种无限内存的计算模式。 ² 编程高效性。程序员不再担心内存治理问题。 引用计数智能指针,有时也称为“计数体术语”,是一种生命期受管的对象,其对引用它的数量,有一个内部的计数器。当内部引用计数为零时,这些对象会自动销毁自身,这是一种非常有用的技术,已运用在许多C++软件产品项目中,因为简单易行,且无需对语言或编译器进行任何扩展。 引用计数智能指针能进一步定义为一体式或分离式,一体式智能指针把引用计数放在自身内,而分离式智能指针则把引用计数放在对象之外。在本文中,使用的是分离式智能指针方案,这需要在访问实际对象指针之前,在智能指针模板对象中重载 - 或 * 操作符,从本质上来说,这也是代理(Proxy)设计模式的一个特例。 就目前来说,还没有一种方案以高效利用内存的方式描述了怎样恢复智能指针,而传统的C++对象串行与反串行化方法,会导致内存低效,因为当一个反串行化的对象碰到一个对它的引用时,总是会创建一个新对象,在最坏的情况下,这会把一个恢复后的守护进程的内存消耗量,推到一个无法接受的高度,致使它无法继续运行下去。 问题的引出 传统对象的串行与反串行化方案,也能实现智能指针,只不过在内存上比较低效而已。在这些传统方案中,当一个对象串行化时,对象内的成员指针被解引用,它的内容与对象一起“串行”进存档文件中。这种方法的问题在于,当反串行化时,成员指针会再次构造,且是每个恢复的对象都会这样。 下面以基于事件的作业调度系统来进行讲解,作业定义在CJobDef对象中,其包含了作业的静态属性,如它执行的命令、工作目录、及作业执行时的用户ID。而作业定义的运行实例则包装在CJobInst对象中,其包含了一些与实例有关的属性,如它的进程ID、执行参数、及运行历史记录。在类层次上,每个CJobInst对象都包含了一个成员,其引用到触发这次作业实例的原始CJobDef对象。 图1是软件停止运行之前的系统,运行时CJobInst对象的多个实例可能会引用至同一个CJobDef对象。在软件停止及恢复后,传统串行化对象恢复方法,会导致为每个运行的CJobInst对象,都创建一个CJobDef对象,如图2中所示。
图1:恢复之前的对象图
图2:内存低效恢复之后的对象图 这种情况发生在传统的C++类对象中指针成员串行化与反串行化时,例1,是一段带有重载与操作符,串行及反串行化CJobInst与CJobDef类指针的CArchive类代码,也证实了这点。 例1:以下是引用片段:
图3:作业定义类关系图 在CJobDefPtr类中,赋值=操作符递增了CJobDef对象CReferable基类中的引用计数,而delete操作符递减了这个引用计数。包装在CJobDefPtr对象中的CJobDef对象不会被销毁,直到它的引用计数为零,这也说明了在系统中,没有其他任何对象引用CJobDef对象,它可以安全地被销毁了。 再次提醒,从作业中创建的作业实例,被包装在一个CJobInst类中。与CJobDef一样,类CScheduler只知道它对应版本的智能指针CJobInstPtr,而此对象的实例也会一直保持到没有对它的引用为止。 另外,在系统中,还包括了另外三个特性,以便使调度系统可高效地恢复: ² 类CReferable增加了一个tag属性,以唯一地识别每个创建的指针实例,同时有一个getTag()方法可用于访问此属性。 ² Ref模板类在称为CReferableCache的全局对象缓存中治理它的对象,此全局对象缓存可由其他智能指针对象访问。 ² Ref模板类添加了一个impersonate()方法,其答应一个智能指针以给定的tag转换为另一个智能指针。 当一个新的CJobDefPtr或CJobInstPtr被创建时,在CReferable基类构造函数中,会分配给对象唯一的一个tag。这个tag可由几种方式产生,但任一种方式都必须保证在每次软件运行时,都会有一个唯一的ID。一个简单的方案是使用一个静态、全局的计数器对象,其在存档文件中存储了上一次产生的ID,由此可保证甚至在有多个软件实例运行的条件下,都能单调不重复地递增此ID。 分配给智能指针的tag,唯一地标识出一个指针,而把此tag存入一个存档文件就是对象串行化过程的责任了。对象的串行化过程,可通过CReferable基类的getTag()方法,来访问此tag,接下来,对象的反串行化过程使用此tag,在软件恢复时,来重建正确的对象指针实例引用。下面是反串行化过程必须执行的步骤: ² 从存档文件中恢复tag。 ² 从tag标识的存档文件中,恢复对象属性。 ² 以此tag为界调用impersonate()方法,恢复正确的指针对象的引用。 Impersonate()会对是否一个tag索引了在全局CReferableCache对象集中的一个对象进行检查,假如未找到此tag相应的对象,那么此对象会添加到CReferableCache中,并用此tag作为它的索引值。然而,假如一个对象已经存在于全局CReferableCache对象集中,通过以新引用来调用set()方法,你可以舍弃老引用,且无关的对象复制操作也会自动被删除。例2使用了这种技术来实现智能指针。 例2:以下是引用片段:
图4:作业对象与CReferableCache全局对象的交互 图4描述了系统中类CScheduler、CJobDefPtr、CJobDef、CReferableCache之间的交互,类CReferableCache具有静态成员方法getUniqueTag()、addObject()、deleteObject()。当一个对CJobDef的智能指针创建时,如下:以下是引用片段:来源:http://www.tulaoshi.com/n/20160219/1626451.html
看过《C++引用计数的智能指针有效回收方法》的人还看了以下文章 更多>>