圖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 |
新聞熱點
疑難解答