• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            woaidongmao

            文章均收錄自他人博客,但不喜標(biāo)題前加-[轉(zhuǎn)貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評(píng)論 - 661, 引用 - 0
            數(shù)據(jù)加載中……

            C++引用計(jì)數(shù)的智能指針有效回收方法

              怎樣從災(zāi)難性故障中,恢復(fù)一個(gè)長(zhǎng)期運(yùn)行、系統(tǒng)級(jí)的后臺(tái)守護(hù)進(jìn)程或者服務(wù),在如今的軟件設(shè)計(jì)過程中,已成為了一個(gè)重要的考慮因素。當(dāng)這些軟件是由C++語言編成,并使用了引用計(jì)數(shù)的智能指針時(shí),那么,智能指針的有效回收,對(duì)系統(tǒng)是否具有可伸縮級(jí)的恢復(fù)能力、甚至正確地繼續(xù)未完成的操作來說,都顯得至關(guān)重要。

              在本文中,描述了一種方法,可從關(guān)機(jī)之后的軟件恢復(fù)中,有效地回收引用計(jì)數(shù)指針,而且此方法在內(nèi)存占用方面也非常高效,這種方法的關(guān)鍵在于避免對(duì)象復(fù)制,而對(duì)象復(fù)制通常是由C++中指針引用的串行化與反串行化這種傳統(tǒng)技術(shù)產(chǎn)生的。當(dāng)從存檔文件中反串行化時(shí),本方法使用了標(biāo)記(tag)來唯一地識(shí)別指針對(duì)象,且在系統(tǒng)恢復(fù)時(shí)由一個(gè)對(duì)象緩存來保存指針引用。

              本文以一個(gè)基于事件的商業(yè)實(shí)時(shí)作業(yè)調(diào)度系統(tǒng)來進(jìn)行演示,其通常由大型市場(chǎng)咨詢公司使用,每天都會(huì)在集群工作站上處理數(shù)不勝數(shù)的計(jì)算任務(wù)。

              為什么許多C++軟件項(xiàng)目會(huì)使用自動(dòng)內(nèi)存管理技術(shù)呢,因?yàn)樗幸韵潞锰帲?span lang="EN-US">

              2 代碼安全性。避免了太早釋放一個(gè)對(duì)象所帶來的風(fēng)險(xiǎn)。

              2 代碼正確性。避免了忘記釋放未使用內(nèi)存所帶來的風(fēng)險(xiǎn)。

              2 代碼模塊性。代碼中不再需要點(diǎn)綴著與程序無關(guān)的簿記代碼。

              2 編程簡(jiǎn)單性。現(xiàn)在可假定一種無限內(nèi)存的計(jì)算模式。

              2 編程高效性。程序員不再擔(dān)心內(nèi)存管理問題。

              引用計(jì)數(shù)智能指針,有時(shí)也稱為計(jì)數(shù)體術(shù)語,是一種生命期受管的對(duì)象,其對(duì)引用它的數(shù)量,有一個(gè)內(nèi)部的計(jì)數(shù)器。當(dāng)內(nèi)部引用計(jì)數(shù)為零時(shí),這些對(duì)象會(huì)自動(dòng)銷毀自身,這是一種非常有用的技術(shù),已運(yùn)用在許多C++軟件產(chǎn)品項(xiàng)目中,因?yàn)楹?jiǎn)單易行,且無需對(duì)語言或編譯器進(jìn)行任何擴(kuò)展。

              引用計(jì)數(shù)智能指針能進(jìn)一步定義為一體式或分離式,一體式智能指針把引用計(jì)數(shù)放在自身內(nèi),而分離式智能指針則把引用計(jì)數(shù)放在對(duì)象之外。在本文中,使用的是分離式智能指針方案,這需要在訪問實(shí)際對(duì)象指針之前,在智能指針模板對(duì)象中重載 -> * 操作符,從本質(zhì)上來說,這也是代理(Proxy)設(shè)計(jì)模式的一個(gè)特例。

              就目前來說,還沒有一種方案以高效利用內(nèi)存的方式描述了怎樣恢復(fù)智能指針,而傳統(tǒng)的C++對(duì)象串行與反串行化方法,會(huì)導(dǎo)致內(nèi)存低效,因?yàn)楫?dāng)一個(gè)反串行化的對(duì)象遇到一個(gè)對(duì)它的引用時(shí),總是會(huì)創(chuàng)建一個(gè)新對(duì)象,在最壞的情況下,這會(huì)把一個(gè)恢復(fù)后的守護(hù)進(jìn)程的內(nèi)存消耗量,推到一個(gè)無法接受的高度,致使它無法繼續(xù)運(yùn)行下去。

              問題的引出

              傳統(tǒng)對(duì)象的串行與反串行化方案,也能實(shí)現(xiàn)智能指針,只不過在內(nèi)存上比較低效而已。在這些傳統(tǒng)方案中,當(dāng)一個(gè)對(duì)象串行化時(shí),對(duì)象內(nèi)的成員指針被解引用,它的內(nèi)容與對(duì)象一起串行進(jìn)存檔文件中。這種方法的問題在于,當(dāng)反串行化時(shí),成員指針會(huì)再次構(gòu)造,且是每個(gè)恢復(fù)的對(duì)象都會(huì)這樣。

              下面以基于事件的作業(yè)調(diào)度系統(tǒng)來進(jìn)行講解,作業(yè)定義在CJobDef對(duì)象中,其包含了作業(yè)的靜態(tài)屬性,如它執(zhí)行的命令、工作目錄、及作業(yè)執(zhí)行時(shí)的用戶ID。而作業(yè)定義的運(yùn)行實(shí)例則包裝在CJobInst對(duì)象中,其包含了一些與實(shí)例有關(guān)的屬性,如它的進(jìn)程ID、執(zhí)行參數(shù)、及運(yùn)行歷史記錄。在類層次上,每個(gè)CJobInst對(duì)象都包含了一個(gè)成員,其引用到觸發(fā)這次作業(yè)實(shí)例的原始CJobDef對(duì)象。

              圖1是軟件停止運(yùn)行之前的系統(tǒng),運(yùn)行時(shí)CJobInst對(duì)象的多個(gè)實(shí)例可能會(huì)引用至同一個(gè)CJobDef對(duì)象。在軟件停止及恢復(fù)后,傳統(tǒng)串行化對(duì)象恢復(fù)方法,會(huì)導(dǎo)致為每個(gè)運(yùn)行的CJobInst對(duì)象,都創(chuàng)建一個(gè)CJobDef對(duì)象,如圖2中所示。

              clip_image001

              圖1:恢復(fù)之前的對(duì)象圖

              clip_image002

              圖2:內(nèi)存低效恢復(fù)之后的對(duì)象圖

              這種情況發(fā)生在傳統(tǒng)的C++類對(duì)象中指針成員串行化與反串行化時(shí),例1,是一段帶有重載>><<操作符,串行及反串行化CJobInstCJobDef類指針的CArchive類代碼,也證明了這點(diǎn)。

              例1

            以下是引用片段:
            classCJobDef
              {
              friendCArchive&operator>>(CArchive&ar,CJobDef*def)
              {
              ar>>def->command;
              }
              friendCArchive&operator<<(CArchive&ar,CjobDef*def)
              {
              ar<<def->command;
              }
              private:
              std::stringcommand;
              };
              classCJobInst
              {
              friendCArchive&operator>>(CArchive&ar,CJobInst*inst)
              {
              inst->m_def=newCJobDef;
              ar>>inst->m_def;
              }
              friendCArchive&operator<<(CArchive&ar,constCJobInst*inst)
              {
              ar<<inst->m_def;
              }
              private:
              CJobDef*m_def;
              };


              在CJobInst中串行化CJobDef的私有成員m_def涉及到調(diào)用CArchive類中適當(dāng)?shù)?span lang="EN-US"><<操作符,重載的<<操作符通過把對(duì)象屬性串行化進(jìn)一個(gè)永久的存檔文件,來實(shí)現(xiàn)對(duì)CJobDef指針的串行化;反串行化CJobDef指針涉及到構(gòu)造一個(gè)新的對(duì)象,并調(diào)用>>操作符從存檔文件中更新屬性。
             
              解決方案
             
              引用計(jì)數(shù)智能指針是由繼承自CReferable類一個(gè)對(duì)象實(shí)現(xiàn)的,其包含了一個(gè)私有引用計(jì)數(shù)器及用于修改其值的increaseReferenceCount()與decreaseReferenceCount()方法,而相應(yīng)的Ref模板類,通過->*= 操作符重載,也實(shí)現(xiàn)了訪問此對(duì)象及對(duì)生命期的管理。Ref模板對(duì)智能指針的賦值操作,會(huì)遞增對(duì)象的引用計(jì)數(shù),而它的析構(gòu)函數(shù)會(huì)遞減計(jì)數(shù)。智能指針中的對(duì)象只當(dāng)它的引用計(jì)數(shù)為零時(shí)被銷毀。在上面的作業(yè)調(diào)度系統(tǒng)中,CJobDef對(duì)象被包裝在一個(gè)CJobDefPtr類型中,其由以下語句定義:
             

            以下是引用片段:
            typedefRef<CJobDef>CJobDefPtr;


            這個(gè)CJobDefPtr類型,正是類CScheduler所用到的類型。當(dāng)用戶提交一個(gè)作業(yè)到事件作業(yè)調(diào)度器時(shí),會(huì)產(chǎn)生一個(gè)CJobDefPtr類型新的對(duì)象,且會(huì)賦予它CJobDef對(duì)象;此后,當(dāng)作業(yè)實(shí)例創(chuàng)建時(shí),也正是這個(gè)CJobDefPtr類型賦予給了實(shí)例。圖3演示了類CScheduler使用的CJobDefPtr類型。

              clip_image003

              圖3:作業(yè)定義類關(guān)系圖

              在CJobDefPtr類中,賦值=操作符遞增了CJobDef對(duì)象CReferable基類中的引用計(jì)數(shù),而delete操作符遞減了這個(gè)引用計(jì)數(shù)。包裝在CJobDefPtr對(duì)象中的CJobDef對(duì)象不會(huì)被銷毀,直到它的引用計(jì)數(shù)為零,這也說明了在系統(tǒng)中,沒有其他任何對(duì)象引用CJobDef對(duì)象,它可以安全地被銷毀了。

              再次提醒,從作業(yè)中創(chuàng)建的作業(yè)實(shí)例,被包裝在一個(gè)CJobInst類中。與CJobDef一樣,類CScheduler只知道它對(duì)應(yīng)版本的智能指針CJobInstPtr,而此對(duì)象的實(shí)例也會(huì)一直保持到?jīng)]有對(duì)它的引用為止。

              另外,在系統(tǒng)中,還包括了另外三個(gè)特性,以便使調(diào)度系統(tǒng)可高效地恢復(fù):

              2 CReferable增加了一個(gè)tag屬性,以唯一地識(shí)別每個(gè)創(chuàng)建的指針實(shí)例,同時(shí)有一個(gè)getTag()方法可用于訪問此屬性。

              2 Ref模板類在稱為CReferableCache的全局對(duì)象緩存中管理它的對(duì)象,此全局對(duì)象緩存可由其他智能指針對(duì)象訪問。

              2 Ref模板類添加了一個(gè)impersonate()方法,其允許一個(gè)智能指針以給定的tag轉(zhuǎn)換為另一個(gè)智能指針。

              當(dāng)一個(gè)新的CJobDefPtrCJobInstPtr被創(chuàng)建時(shí),在CReferable基類構(gòu)造函數(shù)中,會(huì)分配給對(duì)象唯一的一個(gè)tag。這個(gè)tag可由幾種方式產(chǎn)生,但任一種方式都必須保證在每次軟件運(yùn)行時(shí),都會(huì)有一個(gè)唯一的ID。一個(gè)簡(jiǎn)單的方案是使用一個(gè)靜態(tài)、全局的計(jì)數(shù)器對(duì)象,其在存檔文件中存儲(chǔ)了上一次產(chǎn)生的ID,由此可保證甚至在有多個(gè)軟件實(shí)例運(yùn)行的條件下,都能單調(diào)不重復(fù)地遞增此ID

              分配給智能指針的tag,唯一地標(biāo)識(shí)出一個(gè)指針,而把此tag存入一個(gè)存檔文件就是對(duì)象串行化過程的責(zé)任了。對(duì)象的串行化過程,可通過CReferable基類的getTag()方法,來訪問此tag,接下來,對(duì)象的反串行化過程使用此tag,在軟件恢復(fù)時(shí),來重建正確的對(duì)象指針實(shí)例引用。下面是反串行化過程必須執(zhí)行的步驟:

              2 從存檔文件中恢復(fù)tag

              2 tag標(biāo)識(shí)的存檔文件中,恢復(fù)對(duì)象屬性。

              2 以此tag為界調(diào)用impersonate()方法,恢復(fù)正確的指針對(duì)象的引用。

              Impersonate()會(huì)對(duì)是否一個(gè)tag索引了在全局CReferableCache對(duì)象集中的一個(gè)對(duì)象進(jìn)行檢查,如果未找到此tag相應(yīng)的對(duì)象,那么此對(duì)象會(huì)添加到CReferableCache中,并用此tag作為它的索引值。然而,如果一個(gè)對(duì)象已經(jīng)存在于全局CReferableCache對(duì)象集中,通過以新引用來調(diào)用set()方法,你可以舍棄老引用,且無關(guān)的對(duì)象復(fù)制操作也會(huì)自動(dòng)被刪除。例2使用了這種技術(shù)來實(shí)現(xiàn)智能指針。

              例2

            以下是引用片段:
            classCJobDef:publicCReferable
              {
              friendCArchive&operator<<(CArchive&ar,constCJobDefPtr&cand)
              {
              ar<<cand->getTag();
              CArchivear_def(cand->getTag(),CArchive::WRITE);
              //writeobjectattributestoar_def
              returnar;
              }
              friendCArchive&operator>>(CArchive&ar,CJobDefPtr&cand)
              {
              inttag;
              ar>>tag;
              CArchivear_def(tag,CArchive::READ);
              //readobjectattributesfromar_def
              cand.impersonate(tag);
              returnar;
              }
              };
              classCJobInst:publicCReferable
              {
              friendCArchive&operator<<(CArchive&ar,constCJobInstPtr&cand)
              {
              ar<<cand->m_defPtr;
              returnar;
              }
              friendCArchive&operator>>(CArchive&ar,CJobInstPtr&cand)
              {
              CJobDefPtrdefPtr=newCJobDef;
              ar>>defPtr;
              cand->m_defPtr=defPtr;
              returnar;
              }
              };


             clip_image004

              圖4:作業(yè)對(duì)象與CReferableCache全局對(duì)象的交互

              圖4描述了系統(tǒng)中類CSchedulerCJobDefPtrCJobDefCReferableCache之間的交互,類CReferableCache具有靜態(tài)成員方法getUniqueTag()addObject()deleteObject()。當(dāng)一個(gè)對(duì)CJobDef的智能指針創(chuàng)建時(shí),如下:

            以下是引用片段:
            CJobDefPtrjobDefPtr=newCJobDef


                CScheduler會(huì)構(gòu)造CJobDefPtr和一個(gè)CJobDef對(duì)象,當(dāng)對(duì)象構(gòu)造時(shí),會(huì)通過CJobDef基類的CReferable構(gòu)造函數(shù)調(diào)用getUniqueTag()方法,這就為每個(gè)CJobDef對(duì)象創(chuàng)建了一個(gè)唯一的識(shí)別標(biāo)記(tag)。接下來,CJobDef對(duì)象被賦給CJobDefPtr對(duì)象,后者會(huì)調(diào)用它自己的set()方法把CJobDef對(duì)象添加進(jìn)來。

              當(dāng)調(diào)用CJobDefPtr賦值操作符函數(shù)時(shí),也會(huì)調(diào)用addObject()方法,如果是第一次賦值的話,它會(huì)把CJobDef對(duì)象添加進(jìn)全局CReferableCache;當(dāng)智能指針被請(qǐng)求替換由tag識(shí)別的它內(nèi)部的對(duì)象引用時(shí),impersonate()方法會(huì)調(diào)用getObject()方法,如果impersonate()方法未找到CReferableCache中標(biāo)記的對(duì)象,那么,CJobDefPtr對(duì)象會(huì)替換它的內(nèi)部對(duì)象標(biāo)記,并把它自身添加到CReferableCache緩存集中;最后,當(dāng)CJobDefPtr被刪除及對(duì)象的引用計(jì)數(shù)為零時(shí),deleteObject()方法此時(shí)會(huì)被調(diào)用。

              在此所描述的事件調(diào)度系統(tǒng),一般使用在市場(chǎng)咨詢數(shù)據(jù)公司中,其會(huì)在網(wǎng)絡(luò)集群工作站上觸發(fā)計(jì)算任務(wù),當(dāng)從世界各處的零售商匯集所需信息之后,在每周的三天之中,都會(huì)觸發(fā)計(jì)算任務(wù),而這三天中的任意時(shí)刻,系統(tǒng)可能也要在集群工作站上運(yùn)行超過20萬個(gè)任務(wù)。因此,軟件在合理內(nèi)存及CPU消耗的前提下,支持重新啟動(dòng),就顯得非常重要了。表1顯示了在系統(tǒng)中運(yùn)行著多個(gè)計(jì)算任務(wù)時(shí),事件調(diào)度守護(hù)進(jìn)程在每次重啟后的內(nèi)存消耗,在系統(tǒng)重啟后,較小的內(nèi)存消耗要?dú)w功于軟件中使用了上文方法來串行及反串行化不常用的類對(duì)象的那些模塊。當(dāng)任務(wù)完成時(shí),內(nèi)存最終將被回收。

              表1:在軟件每次重啟后的調(diào)度系統(tǒng)所用內(nèi)存大小

            運(yùn)行任務(wù)數(shù)

            軟件重啟前的內(nèi)存占用大小

            軟件重啟后的內(nèi)存占用大小

            5000

            25M

            32M

            100000

            370M

            413M

            200000

            730M

            795M

             

            posted on 2009-08-26 13:26 肥仔 閱讀(472) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++ 基礎(chǔ)

            精品久久久久久久国产潘金莲 | 久久亚洲日韩看片无码| 国产人久久人人人人爽| 欧美大香线蕉线伊人久久| 精品国产乱码久久久久软件| 国产精品美女久久久久AV福利| 国产精品99久久久久久宅男 | 狠狠色丁香久久婷婷综合五月| 久久亚洲精品成人无码网站| 亚洲人成无码www久久久| 狠狠色婷婷久久综合频道日韩| WWW婷婷AV久久久影片| 国内精品久久久久久99蜜桃| 精品国产乱码久久久久久郑州公司 | 亚洲AV无码久久| 好属妞这里只有精品久久| 久久精品成人免费观看97| 国内精品九九久久精品 | 久久精品人人做人人爽97 | 久久久精品国产亚洲成人满18免费网站 | 精品久久久久久国产| 一本大道加勒比久久综合| 国产精品久久新婚兰兰| 久久久亚洲裙底偷窥综合| 国产成人综合久久精品尤物| 久久久WWW成人免费毛片| 少妇久久久久久被弄到高潮| 久久午夜电影网| 无码精品久久久天天影视| 国产精品欧美久久久天天影视| 久久天天躁夜夜躁狠狠躁2022| 97久久国产露脸精品国产| 久久久青草久久久青草| 久久精品国产72国产精福利| 久久国产精品无| 国产精品九九九久久九九| 国内精品伊人久久久久影院对白| 国内精品九九久久久精品| 国内精品久久久久久久亚洲| 伊人久久大香线蕉av不卡| 国产日韩久久久精品影院首页|