1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        在嵌入式中,如何正確使用動態(tài)內(nèi)存?

        共 5985字,需瀏覽 12分鐘

         ·

        2022-01-19 11:33

        ????關(guān)注、星標(biāo)公眾號,直達(dá)精彩內(nèi)容

        來源:jiangjunjie_2005


        一. ?常見錯誤與預(yù)防

        1. ? 分配后忘記釋放內(nèi)存

        void?func(void)
        {
        ????p?=?malloc(len);
        ????do_something(p);
        ????return;??/*錯誤!退出程序時沒有釋放內(nèi)存*/
        }

        預(yù)防:?編寫代碼時malloc()和free()保證成對出現(xiàn),避免忘記資源回收。

        int?func(void)
        {
        ????p?=?malloc(len);
        ????if?(condition)
        ????????return?-1;??/*錯誤!退出程序時沒有釋放內(nèi)存*/
        ????free(p);
        ????return?0;
        }

        預(yù)防:?一旦使用動態(tài)內(nèi)存分配,請仔細(xì)檢查程序的退出分支是否已經(jīng)釋放該動態(tài)內(nèi)存。

        2. ? 釋放內(nèi)存調(diào)用錯誤指針

        void?func(void)
        {
        ????p?=?malloc(len);
        ????val?=?*p++;??/*錯誤!動態(tài)內(nèi)存句柄不可移動*/
        ????free(p);
        }

        預(yù)防:?千萬不要修改動態(tài)內(nèi)存句柄!可以另外賦值給其他指針變量,再對該動態(tài)內(nèi)存進行訪問操作。

        3. ? 分配內(nèi)存不夠?qū)е乱绯?/span>

        void?func(void)
        {
        ????len?=?strlen(str);
        ????p?=?malloc(len);
        ????strcpy(p,?str);??/*錯誤!str的’\0’寫到動態(tài)內(nèi)存外*/
        }

        預(yù)防:?分配內(nèi)存前仔細(xì)思考長度是否足夠,千萬注意字符串拷貝占用內(nèi)存比字符串長度大1。

        二. ?自動查錯機制

        盡管在開發(fā)過程中堅守原則和謹(jǐn)慎編程甚至嚴(yán)格測試,然而內(nèi)存泄露的錯誤還是難以杜絕,如何讓系統(tǒng)自動查出內(nèi)存泄露的錯誤呢?

        一種比較好的方法是建立日志塊,即每次分配內(nèi)存時記錄該內(nèi)存塊的指針和大小,釋放時再去除該日志塊,如果有內(nèi)存泄露就會有對應(yīng)的日志塊記錄這些內(nèi)存沒有釋放,這樣就可以提醒程序員進行查錯。

        有了上述日志塊操作函數(shù),再來實現(xiàn)動態(tài)內(nèi)存分配與釋放函數(shù)就很容易了。只有當(dāng)處于DEBUG版本和打開內(nèi)存調(diào)試DMEM_DBG時才進行日志登錄,否則MallocExt()和FreeExt()函數(shù)與malloc()和free()是等價的,這樣保證了系統(tǒng)處于發(fā)布版本時的性能。

        (代碼已經(jīng)過嚴(yán)格測試,但這不是盈利的商業(yè)代碼,即沒有版權(quán)。但如果因代碼錯誤帶來的任何損失作者具有免責(zé)權(quán)利)

        代碼部分:

        首先定義日志塊結(jié)構(gòu)體:

        /*?Log?of?dynamic?memory?usage?*/
        typedef?struct?_dmem_log
        {

        ????struct?_dmem_log?*p_stNext;?/*?Point?to?next?log?*/
        ????const?void?*p_vDMem;?/*?Point?to?allocated?memory?by?this?pointer?*/
        ????INT32S?iSize;?/*?Size?of?the?allocated?memory?*/
        }?DMEM_LOG;

        然后為該結(jié)構(gòu)體開辟內(nèi)存:

        static?DMEM_LOG?*s_pstFreeLog;?/*?Point?to?free?log?pool?by?this?pointer?*/
        static?INT8U?s_byNumUsedLog;
        static?DMEM_LOG?*s_pstHeadLog;?/*?Point?to?used?log?chain?by?this?pointer?*/

        /*?Pool?of?dynamic?memory?log?*/
        #define?NUM_DMEM_LOG?20
        static?DMEM_LOG?s_astDMemLog[NUM_DMEM_LOG];

        下面是內(nèi)存日志塊的操作函數(shù):初始化、插入日志和移除日志:

        /**********************************************************?????????????????????????????????????????????????????????????*????????????????????Initialize?DMem?Log
        *?Description?:?Initialize?log?of?dynamic?memory
        *?Arguments??:?void
        *?Returns??????:?void
        *?Notes????????:
        **********************************************************/

        static?void?InitDMemLog(void)
        {
        ????INT16S????nCnt;
        ????/*?Initialize?pool?of?log?*/
        ????for?(nCnt?=?0;?nCnt?????{
        ????????/*?Point?to?next?one?*/
        ????????s_astDMemLog[nCnt].p_stNext?=?&s_astDMemLog[nCnt?+?1];
        ????}
        ????s_astDMemLog[NUM_DMEM_LOG?-?1].p_stNext?=?NULL;
        ????s_pstFreeLog?=?&s_astDMemLog[0];?/*?Point?to?the?1th?log?*/
        ????return;
        }

        /**********************************************************?????????????????????????????????????????????????????????????*???????????????????????Log?DMem
        *?Description?:?Join?an?allocated?memory?into?log?pool
        *?Arguments??:?const?void?*p_vAddr????point?to?address?of?this?allocated?memory?by?this?pointer
        *?????????????INT32S?iSize????size?of?this?allocated?memory
        *?Returns??????:?void
        *?Notes????????:
        **********************************************************/

        static?void?LogDMem(const?void?*p_vAddr,?INT32S?iSize)
        {
        ????ASSERT(p_vAddr?&&?iSize?>?0);
        ????DMEM_LOG?*p_stLog;
        ????#if?OS_CRITICAL_METHOD?==?3
        ????OS_CPU_SR??cpu_sr;
        ????#endif
        ????
        ????/*?Get?a?log?from?free?pool?*/
        ????OS_ENTER_CRITICAL();?/*?Avoid?race?condition?on?s_pstFreeLog?*/
        ????if?(!s_pstFreeLog)
        ????{
        ????????OS_EXIT_CRITICAL();
        ????????PRINTF("Allocate?DMemLog?failed.\r\n");???????
        ????????return;
        ????}
        ????p_stLog?=?s_pstFreeLog;
        ????s_pstFreeLog?=?s_pstFreeLog->p_stNext;
        ????OS_EXIT_CRITICAL();
        ????
        ????/*?Don't?need?to?protect?this?log?that?is?free?one?currently?*/
        ????p_stLog->p_vDMem?=?p_vAddr;
        ????p_stLog->iSize?=?iSize;

        ????/*?Put?this?log?into?used?chain?*/
        ????OS_ENTER_CRITICAL();?/*?Avoid?race?condition?*/
        ????p_stLog->p_stNext?=?s_pstHeadLog;
        ????s_pstHeadLog?=?p_stLog;
        ????++s_byNumUsedLog;
        ????OS_EXIT_CRITICAL();
        ????
        ????return;
        }

        /**********************************************************?????????????????????????????????????????????????????????????*???????????????????????Unlog?DMem
        *?Description?:?Remove?an?allocated?memory?from?log?pool
        *?Arguments??:?const?void?*p_vAddr?point?to?address?of?this?allocated?memory?by?this?pointer
        *?Returns??????:?void
        *?Notes????????:
        **********************************************************/

        static?void?UnlogDMem(const?void?*p_vAddr)
        {
        ????ASSERT(p_vAddr);
        ????DMEM_LOG????*p_stLog,?*p_stPrev;
        ????#if?OS_CRITICAL_METHOD?==?3
        ????OS_CPU_SR??cpu_sr;
        ????#endif

        ????/*?Search?the?log?*/
        ????OS_ENTER_CRITICAL();?/*Avoid?race?condition?*/
        ????p_stLog?=?p_stPrev?=?s_pstHeadLog;
        ????while?(p_stLog)
        ????{
        ????????if?(p_vAddr?==?p_stLog->p_vDMem)
        ????????{
        ?????????break;?/*?Have?found?*/
        ????????}??????????

        ????????p_stPrev?=?p_stLog;????????
        ????????p_stLog?=?p_stLog->p_stNext;????/*?Move?to?next?one?*/
        ????}
        ????
        ????if?(!p_stLog)
        ????{
        ????????OS_EXIT_CRITICAL();
        ????????PRINTF("Search?Log?failed.\r\n");?????????
        ????????return;
        ????}

        ????/*?Remove?from?used?pool?*/
        ????if?(p_stLog?==?s_pstHeadLog)
        ????{
        ?????s_pstHeadLog?=?s_pstHeadLog->p_stNext;
        ????}
        ????else
        ????{
        ?????p_stPrev->p_stNext?=?p_stLog->p_stNext;
        ????}
        ????--s_byNumUsedLog;
        ????OS_EXIT_CRITICAL();

        ????/*?Don't?need?to?protect?this?log?that?is?free?one?currently?*/
        ????p_stLog->p_vDMem?=?NULL;
        ????p_stLog->iSize?=?0;

        ????/*?Add?into?free?pool?*/
        ????OS_ENTER_CRITICAL();?/*?Avoid?race?condition?*/
        ????p_stLog->p_stNext?=?s_pstFreeLog;
        ????s_pstFreeLog?=?p_stLog;
        ????OS_EXIT_CRITICAL();

        ????return;
        }

        帶日志記錄功能的內(nèi)存分配MallocExt()和內(nèi)存釋放FreeExt()函數(shù):

        /*********************************************************????????????????????????????????????????????????????
        *??????????????????????Malloc?Extension
        *?Description?:?Malloc?a?block?of?memory?and?log?it?if?need
        *?Arguments?:?INT32S?iSize????size?of?desired?allocate?memory
        *?Returns:?void?*NULL=?failed,?otherwise=pointer?of?allocated?memory
        *?Notes????????:
        **********************************************************/

        void?*MallocExt(INT32S?iSize)
        {
        ????ASSERT(iSize?>?0);
        ????void?*p_vAddr;

        ????p_vAddr?=?malloc(iSize);
        ????if?(!p_vAddr)
        ????{
        ?????PRINTF("malloc?failed?at?%s?line?%d.\r\n",?__FILE__,?__LINE__);
        ????}
        ????else
        ????{
        ????????#if?(DMEM_DBG?&&?DBG_VER)
        ????????memset(p_vAddr,?0xA3,?iSize);?/*?Fill?gargage?for?debug?*/
        ????????LogDMem(p_vAddr,?iSize);????/*?Log?memory?for?debug?*/
        ????????#endif
        ????}

        ????return?p_vAddr;?????
        }

        /**********************************************************
        *??????????????????????Free?Extension
        *?Description?:?Free?a?block?of?memory?and?unlog?it?if?need
        *?Arguments??:?void?*?p_vMem?point?to?the?memory?by?this?pointer
        *?Returns??????:?void
        *?Notes????????:
        **********************************************************/

        void?FreeExt(void?*p_vMem)
        {
        ????ASSERT(p_vMem);

        ????free(p_vMem);??
        ????#if?(DMEM_DBG?&&?DBG_VER)
        ????UnlogDMem(p_vMem);????/*?Remove?memory?from?log?*/
        ????#endif
        ????return;
        }

        原文鏈接:https://blog.csdn.net/jiangjunjie_2005/article/details/26937879

        版權(quán)歸原作者所有,如有侵權(quán),請聯(lián)系刪除。

        ???????????????? ?END ?????????????????

        關(guān)注我的微信公眾號,回復(fù)“加群”按規(guī)則加入技術(shù)交流群。

        關(guān)注公眾號,回復(fù)“pdf”獲取程序員必讀經(jīng)典書單,一起編程一起進階。



        點擊“閱讀原文”查看更多分享,歡迎點分享、收藏、點贊、在看。

        瀏覽 31
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产无码人妻 | 一边吃奶一边操 | 黄色二区 | 成人毛片免费观看视频 | 欧美操B视频 | 小舞胸啊嗯~高潮了 | 我要看黄色1级片 | 欧美性感操逼 | 性乱伦小说| 青草久久久久 |