图1:恢复之前的对象图
图2:内存低效恢复之后的对象图 这种情况发生在传统的C++类对象中指针成员串行化与反串行化时,例1,是一段带有重载>>与<<操作符,串行及反串行化CJobInst与CJobDef类指针的CArchive类代码,也证实了这点。 例1:| 以下是引用片段: class CJobDef { friend CArchive & Operator >> (CArchive &ar, CJobDef *def) { ar >> def->command; } friend CArchive & operator << (CArchive &ar, CjobDef *def) { ar << def->command; } private: std::string command; }; class CJobInst { friend CArchive & operator >> (CArchive &ar, CJobInst *inst) { inst->m_def = new CJobDef; ar >> inst->m_def; } friend CArchive & operator << (CArchive &ar, const CJobInst *inst) { ar << inst->m_def; } private: CJobDef *m_def; }; |
| 以下是引用片段: typedef Ref<CJobDef> CJobDefPtr; |
图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:| 以下是引用片段: class CJobDef : public CReferable { friend CArchive &operator << (CArchive &ar, const CJobDefPtr &cand) { ar << cand->getTag(); CArchive ar_def(cand->getTag(), CArchive::WRITE); // write object attributes to ar_def return ar; } friend CArchive &operator >> (CArchive &ar, CJobDefPtr &cand) { int tag; ar >> tag; CArchive ar_def(tag, CArchive::READ); // read object attributes from ar_def cand.impersonate(tag); return ar; } }; class CJobInst : public CReferable { friend CArchive & operator << ( CArchive &ar, const CJobInstPtr &cand) { ar << cand->m_defPtr; return ar; } friend CArchive & operator >> (CArchive &ar, CJobInstPtr &cand) { CJobDefPtr defPtr = new CJobDef; ar >> defPtr; cand->m_defPtr = defPtr; return ar; } }; |
图4:作业对象与CReferableCache全局对象的交互 图4描述了系统中类CScheduler、CJobDefPtr、CJobDef、CReferableCache之间的交互,类CReferableCache具有静态成员方法getUniqueTag()、addObject()、deleteObject()。当一个对CJobDef的智能指针创建时,如下:| 以下是引用片段: CJobDefPtr jobDefPtr = new CJobDef |
| 运行任务数 | 软件重启前的内存占用大小 | 软件重启后的内存占用大小 |
| 5000 | 25M | 32M |
| 100000 | 370M | 413M |
| 200000 | 730M | 795M |
新闻热点
疑难解答