青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

S.l.e!ep.¢%

像打了激速一樣,以四倍的速度運轉,開心的工作
簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

C++編碼中減少內存缺陷的方法和工具

程振林,方金云,唐志敏
(中國科學院計算技術研究所,北京 100080)


摘 要:基于C++的軟件的缺陷和錯誤大部分都和內存相關,預防、發現、消除代碼中和內存相關的缺陷,成為程序員編寫、調試、維護代碼時的重要任務。該文基于“面向網絡海量空間信息的大型GIS”課題的工程實踐,提出和總結了如何使用C++語言機制、開發環境和相關質量保證工具來預防、發現各種編譯期、運行期內存缺陷的方法和工具。

關鍵詞:C++;內存錯誤;內存泄漏;質量保證

Techniques and Tools of Defending Memory-related Defects in Software Coded in C++
CHENG Zhenlin, FANG Jinyun, TANG Zhimin
(Institute of Computing Technology, Chinese Academy of Sciences, Beijing 100080)
【Abstract】Most of the defects and errors in the software coded in C++ are memory-related. Based on the practice in the "network, large volumespatial information oriented GIS" project, this paper presentsthe techniques and tools to find and fix the memory problems during the coding,debugging and production release phase with the support of the C++ language mechanism, development environment and related quality-assurancetools.
【Key words】C++; Memory errors; Memory leak; Quality assurance

C++語言是桌面系統,尤其是系統軟件、大型應用軟件的主流開發語言。C++語言以其靈活性著稱,同時也更復雜。利用C++編寫健壯的代碼,更具有挑戰性。C++允許動態內存管理, 同時也容易導致更多和內存相關的問題。一般而言, 除了系統設計上的缺陷, 基于C++的軟件的缺陷和錯誤大部分都和內存缺陷(主要包括內存訪問錯誤和內存泄漏兩類)相關。 所以,消除代碼中的內存相關缺陷,成為程序員編寫、調試、維護代碼中的任務,也是保證軟件質量的關鍵。
本文的工作基于“863”計劃項目“面向網絡海量空間信息的大型GIS”課題。該系統是基于C++/MFC編寫,開發環境是Visual Studio .net 2003。本文基于此項目的工程實踐,總結了如何使用C++語言機制、開發環境和相關質量保證工具來預防、發現各種編譯期、運行期和內存相關的缺陷的方法和工具。
1 遵循C++相關的編碼規范和慣用法,預防缺陷
編碼規范是語言相關的規則,是經過實踐總結出來的經驗。良好的編程標準將有效地幫助開發人員避免開發有潛在危險的代碼。一般來說,為了減少內存缺陷,應該遵循下列編碼規則[1]:
(1)基類或者帶有虛函數的類應該將其析構函數聲明為虛函數。
(2)在構造函數中防止內存泄漏,在析構函數中不要拋出異常。
(3)使用對應形式的new和delete。即:用delete來釋放new申請的內存,delete[]釋放new[]申請的內存。
(4)指針在使用前必須初始化,指向動態內存的指針在釋放后應立即置為空。
(5)如果類構造函數中分配了資源,那么需要顯式提供拷貝構造函數和賦值操作符,并且在析構函數中釋放資源。
值得重視的是C++中的慣用法RAII。RAII核心思想是利用對象來管理資源,在對象的構造函數中獲取資源,在其析構函數中釋放資源[2]。為了保證動態申請的內存能在即使出現異常的情況下仍能釋放,比較理想的方法是使用局部變量來管理動態內存的所有權(ownership),就是所謂的智能指針。STL中的auto_ptr就是為解決資源所有權問題設計的,但是缺少對引用數和數組的支持并且不能用在STL容器中。Boost庫[3]提供的智能指針相對成熟,實用價值高。其中,shared_ptr線程安全并且可以用在STL容器中。具體示例參考文獻[3]。
1.1 編碼規范檢查工具 CodeWizard
CodeWizard能夠對源程序直接進行自動掃描、分析和檢查。一旦發現違例,產生信息告知與哪條規則不符并作出解釋。以CodeWizard 4.3 為例,其中內置了超過500條編碼標準。CodeWizard可以選擇對于當前的工程執行哪些編碼標準。CodeWizard可以和VC++緊密集成,安裝完畢以后,VC++中有CodeWizard工具條。
1.2 代碼檢查工具 PC-Lint
PC-Lint可檢查編譯器不易發現的錯誤。PC-Lint可對100多個C庫函數進行檢查,可以發現標準C/C++代碼中的1 000多個常見錯誤。要把PC-lint和Visual Studio集成在一起,需要自己配置。Jon Zyzyck提供了一個報告生成器,可以幫助完成這個工作。可在http://www.ddj.com下載。文獻[4]說明了如何在VC++環境中集成PC-Lint。
2 利用語言機制、開發環境和相關工具以預防和發現內存缺陷
發現問題是解決問題的前提。相對于修復內存缺陷,發現內存缺陷并準確定位導致缺陷的代碼更為費時費力。及早準確地發現內存缺陷,對于提高開發效率非常重要。
2.1 利用斷言及早暴露內存缺陷
斷言是布爾調試語句,用來檢測在程序運行的時候某一條件的值是否總為真。斷言經常用來確認函數的輸入、輸出,檢查對象的當前狀態是否合法等。 在以下的場景使用斷言可以幫助發現和內存非法訪問相關的錯誤:
(1)驗證指針是否可讀/寫。在函數的入口處,經常需要驗證指針所指向的內容區域是否可讀/寫。 通常采用assert(p!= NULL)的檢測形式。 但是,指針的值不為空并不代表指針指向了合法可讀/寫內存。Win32 API提供了函數IsBadReadPtr、IsBadWritePtr、IsBadStringPtr、IsBadCodePtr用來檢測指針指向的內存區域是否可讀/寫。C運行時庫提供了_CrtIs ValidPointer、_CrtIsValidHeapPointer等函數,MFC庫提供了AfxIsValidAddress、AfxIsValidString函數來完成類似功能。
(2)對基于MFC的程序,ASSERT_VALID宏通過調用重載的AssertValid函數來確定指向CObject派生類對象的指針是否有效。ASSERT_VALID宏主要調用了AfxIsValidAddress函數和CObject派生類對象的AssertValid函數(參考MFC源代碼afx.h、objcore.cpp)。
2.2 利用C運行時刻庫檢查內存泄漏
VC++的C運行庫(CRT)提供了廣泛的功能,幫助用戶檢測內存泄漏。CRT提供了_CrtMemCheckPoint、_CrtDump MemoryLeaks、_CrtSetDbgFlag等函數來幫助調試內存泄漏。
對于非MFC的工程, 要開啟有效的內存泄漏報告功能, 需要進行如下設置:

(1)在StdAfx.h的頭部添加如下代碼并開啟編譯器/Yu 選項:

        #define _CRTDBG_MAP_ALLOC
        #include <stdlib.h>
        #include <crtdbg.h>
        #define DEBUG_NEW new(_NORMAL_BLOCK, THIS_FILE, __LINE__)

(2)確保在每個.cpp文件的頭部包含以下內容:
        #include "stdafx.h"
        #ifdef _DEBUG
        #define new DEBUG_NEW
        #undef THIS_FILE
        static char THIS_FILE[] = __FILE__;
        #endif

(3)在程序的開始處開啟報告內存泄漏的開關:
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
對于MFC工程, MFC已經做了相關的工作, 只需要確認在每個.cpp文件的頭部包含上述第(2)點的內容。
在某些情況下,需要知道發生內存泄漏的內存塊中的內容,但是標準的內存轉儲只是內存塊頭部的十六進制形式。為了得到更多的有用信息,需要以用戶塊類型(_CLIENT_ BLOCK)申請內存,并利用_CrtSetDumpClient建立用戶塊型內存的轉儲函數。具體的說,對于不是從CObject繼承的類,需要:

(1)為每個類/結構指定一個用戶塊子類型(參考crtdbg.h)。

(2)在申請內存時,采用重載的new形式:void* __cdecl operator new(size_t nSize, int nType, LPCSTR lpszFileName, int nLine)(參考MFC源代碼 afxmem.cpp),其中nType就是用戶塊的子類型。

(3)創建一個用戶塊內存轉儲函數,專門對每種需要轉儲的子類型進行處理(需要包含dbgint.h)。

(4)利用_CrtSetDumpClient對用戶塊內存轉儲函數進行注冊(參考MFC源代碼dumpinit.cpp)。

對于從CObject繼承來的類,MFC 已經按照上述方法做了基礎工作(參考MFC源代碼 afxmem.cpp、dumpinit.cpp)。要有效轉儲從CObject繼承的對象,需要:(1)對每個從CObject繼承的類重載虛函數Dump。(2)在程序的初始化部分 加入代碼 afxDump.SetDepth(1)來開啟深度轉儲。

2.3 利用Purify和Insure++查找運行時內存缺陷
Rational Purify和Parasoft Insure++ 是用于運行時錯誤檢查的工具。Purify主要檢測:數組內存越界讀/寫,使用未初始化的內存,對已釋放的內存進行讀/寫,內存泄漏等。Insure++利用其專利技術(源碼插裝和運行時指針跟蹤)能夠發現大量的內存操作錯誤,報告錯誤的源代碼行和執行軌跡。根據筆者的測試(基于98個有各種內存錯誤的C++程序,涵蓋了典型情形),Insure++ 6.1都能準確檢測。
3 利用VC++環境的調試和診斷功能,檢查和發現常見內存缺陷
理解常見的內存缺陷問題以及在VC++環境下的癥狀,能輔助我們減少問題的發生和及時修改問題。
從錯誤的表現形式上看, 和堆棧有關的錯誤主要分為兩大類:堆棧溢出和函數返回信息被破壞。

(1)堆棧溢出(overflow)

此類錯誤主要有兩種情形:

1)過大的局部變量。缺省情況下Windows為每個線程保留1M堆棧空間。在菜單Project->Properties->Configuration Properties -> Linker->System中可以看到Stack Reserve Size選項可以調整保留的堆棧空間大小。

2)遞歸調用層數過深。在調試過程中,調用堆棧(call stack)窗口中可以發現函數遞歸調用的模式。

(2)函數返回信息被破壞

此類錯誤主要有兩種情形:
1)對局部變量的寫操作超出了范圍(上溢)。在調試過程中,函數堆棧被破壞掉的明顯標志是無法顯示調用堆棧,并且錯誤發生在被調用函數即將返回的位置。
2)在調用函數和被調用函數之間如果出現了函數參數的不匹配或者調用規范的不一致。
為了檢查此類錯誤,應該在代碼編譯時打開/GS、/RTCs開關(在菜單Project->Properties->Configuration Properties-> C/C++->Code Generation下設置)。
另外一類錯誤是動態內存錯誤。典型的情況如下:
(1)內存寫越界。在調試版本中,如果是寫上溢,就會收到“Damage:after block...”的跟蹤消息,如果是寫下溢出就會收到“Damage: before block...”的跟蹤消息。
(2)刪除不合法指針。在調試版本中,刪除未初始化的指針或者非堆指針時,會收到_CrtIsValidHeapPointer斷言錯誤。
(3)多次釋放。在調試版本中,如果多次刪除同一指針, 會收到_BLOCK_TYPE_IS_VALID斷言錯誤。要防止此類錯誤,應在delete某個指向動態內存的指針后立即將其置為空。

4 利用Windows結構化異常處理機制處理發布版本軟件的內存崩潰
在程序的發布階段,應盡量減少程序錯誤尤其是內存崩潰。如果崩潰了,應該“優雅”地退出,盡量收集程序崩潰時的運行信息以幫助程序供應商后續的調試。要捕捉內存非法訪問并獲知非法訪問的指令地址、寄存器內容等信息,需要用到Windows的結構化異常處理(Structured Exception Handling,SEH)機制[6]。MiniDumpWriteDump是dbghelp.dll提供的一個 API函數(參考MSDN),用于轉儲用戶模式程序的一些信息(比如堆棧情況等)并存為一個文件(比如.dmp文件),此文件可以被微軟的調試器(VC++或者WinDBG)利用進行事后調試。使用此函數需要dbghelp.h、dbghelp.lib和dbghelp.dll(這些文件可以在Windows Platform SDK中找到)。
要事后根據.dmp文件調試代碼,需要為發布版本軟件產生debug symbols (pdb)文件(打開編譯器/DEBUG選項)。在拿到.dmp文件以后,用VC++打開.dmp文件,然后調試執行(按F5鍵)。這樣,崩潰現場就會重現。文獻[5]基于上述的方法實現了崩潰報告系統。

5 結論
實踐證明,在上述方法和工具支持下的減少軟件內存缺陷的方法和工具,可以有效防止和查找代碼中的內存錯誤和內存泄漏,并且能和開發人員日常編碼無縫結合,執行起來非常高效。上述方法配合單元測試、代碼評審、每日構建、Bug追蹤等措施,形成了一個高效的質量保證流程,在我們的大型平臺軟件開發過程中起到了重要作用。

參考文獻
1 Sutter H, Alexandrescu A. C++ Coding Standards: 101 Rules, Guidelines, and Best Practices[M]. Addison-Wesley Professional, 2004-10.
2 Stroustrup B. The Design and Evolution of C++[M]. Addison-Wesley Professional, 1994-03.
3 Karlsson B. Beyond the C++ Standard Library: An Introduction to Boost[M]. Addison-Wesley Professional, 2005-08.
4 Zyzyck J. A Report Generator for PC-Lint[J]. Dr. Dobb's Journal, 2003, 28(2): 52.
5 Dietrich H. XCrash Report: Exception Handling and Crash Reporting[Z]. 2003-10. http://www.codeproject.com/debug/ XCrash ReportPt4.asp.
6 Richter J M. Programming Applications for Microsoft Windows[M]. Microsoft Press, 1999-09.
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            一本到12不卡视频在线dvd| 好男人免费精品视频| 国产一二精品视频| 欧美在线不卡| 欧美a级片网| 久久成人在线| 免费日韩av电影| 午夜久久影院| 欧美成人精品不卡视频在线观看| 亚洲视频大全| 91久久久久久| 午夜影院日韩| 亚洲男人第一av网站| 久久精品麻豆| 亚洲国产精品免费| 欧美成人亚洲成人| 欧美中文字幕在线| 欧美日韩在线观看一区二区三区| 欧美另类极品videosbest最新版本| 亚洲午夜三级在线| 欧美日本中文字幕| 久久久久久电影| 国产手机视频精品| 久久综合久久综合九色| 亚洲人体影院| 亚洲欧美日韩国产一区二区| 精品成人一区二区| 欧美日韩一区国产| 中文网丁香综合网| 玖玖玖免费嫩草在线影院一区| 国内伊人久久久久久网站视频| 久久亚洲精品一区二区| 亚洲精品影院| 久久爱www久久做| 中文日韩在线| 在线精品视频一区二区| 国产精品久久久一区麻豆最新章节| 国产精品99久久不卡二区| 欧美一区二区三区四区在线| 99国产精品国产精品毛片| 一区二区视频在线观看| 国产精品高清免费在线观看| 欧美日韩另类在线| 欧美福利视频一区| 久久一区免费| 老司机午夜精品视频在线观看| 久久se精品一区精品二区| 一区二区欧美日韩| 日韩视频久久| 国内精品模特av私拍在线观看| 欧美日韩和欧美的一区二区| 巨乳诱惑日韩免费av| 久久久久久尹人网香蕉| 久久综合色播五月| 欧美国产三级| 国产精品对白刺激久久久| 国产精品午夜国产小视频| 国产日韩欧美一区| 亚洲国产精品一区二区久| 夜夜嗨av一区二区三区免费区| 亚洲视屏一区| 鲁大师影院一区二区三区| 欧美高清一区二区| 正在播放亚洲一区| 老巨人导航500精品| 欧美日韩在线视频观看| 国产字幕视频一区二区| 日韩一级大片| 久久免费高清视频| 亚洲三级视频| 久久精品欧美日韩| 欧美精品一区二区三区视频 | 欧美日韩精品中文字幕| 欧美大片va欧美在线播放| 国产精品成av人在线视午夜片| 国产性色一区二区| 亚洲影院在线观看| 牛人盗摄一区二区三区视频| 一区二区三区成人精品| 欧美va天堂在线| 在线观看国产欧美| 欧美一区中文字幕| 亚洲一区二区在线播放| 欧美午夜宅男影院| 亚洲一区免费观看| 99这里只有久久精品视频| 欧美精品18| 欧美精品一区二区精品网| 黄色成人在线网站| 久久这里只精品最新地址| 午夜精品视频网站| 国产日韩精品一区二区三区在线| 亚洲一区免费网站| 亚洲欧美日韩国产成人精品影院| 国产精品专区第二| 久久久久久久综合| 久久偷窥视频| 亚洲乱码国产乱码精品精可以看| 亚洲日本电影在线| 国产精品欧美一区二区三区奶水 | 亚洲精品日日夜夜| 久久国产一区| 性久久久久久久久久久久| 亚洲国产精品久久久久秋霞蜜臀 | 欧美bbbxxxxx| 国产婷婷色一区二区三区| 亚洲精品免费在线| 国产精品久久久久久av下载红粉| 午夜精品久久久久久久男人的天堂 | 久久精品国产亚洲精品| 亚洲国产精品国自产拍av秋霞| 99这里有精品| 亚洲精品影院| 久久久久久9999| 中文一区二区| 欧美成人一区二区三区片免费| 亚洲欧美日韩精品久久亚洲区| 另类专区欧美制服同性| 久久精品一二三| 国产婷婷一区二区| 亚洲欧美激情一区| 性欧美大战久久久久久久免费观看 | 亚洲国产精品精华液网站| 欧美亚洲专区| 久久久久九九九| 激情小说亚洲一区| 久久人人爽人人爽爽久久| 巨胸喷奶水www久久久免费动漫| 国产精品久久久久99| 亚洲高清不卡av| 亚洲欧美成人一区二区三区| 国产精品久久久久久模特 | 国产精品影院在线观看| 亚洲永久免费av| 美女主播一区| 亚洲综合日韩中文字幕v在线| 国产亚洲综合精品| 欧美激情区在线播放| 午夜国产精品视频免费体验区| 欧美va亚洲va香蕉在线| 欧美中文日韩| 亚洲主播在线播放| 国产主播在线一区| 免费在线观看精品| 一区二区三区色| 欧美成人国产一区二区| 亚洲五月婷婷| 亚洲国产精品ⅴa在线观看| 欧美色大人视频| 久久久青草青青国产亚洲免观| 欧美激情中文字幕一区二区| 午夜精品久久久99热福利| 国产亚洲一区二区三区在线观看 | 亚洲一区三区视频在线观看| 猛男gaygay欧美视频| 久久精品天堂| 欧美亚洲网站| 性做久久久久久久久| 久久福利电影| 狂野欧美一区| 亚洲欧洲日本在线| 亚洲人成啪啪网站| 亚洲精品日韩在线观看| 亚洲精品在线视频观看| 亚洲日本aⅴ片在线观看香蕉| 激情视频亚洲| 亚洲人久久久| 性欧美精品高清| 久久综合久久久| 日韩视频免费看| 久久在线精品| 国产美女精品视频免费观看| 久久精品一区二区国产| 国产欧美日本一区视频| 亚洲欧美日韩在线观看a三区| 亚洲作爱视频| 免费日韩视频| 黄色成人av在线| 欧美在线观看视频一区二区三区| 久久久在线视频| 国产精品天美传媒入口| 亚洲欧美国产一区二区三区| 久久成人一区| 日韩亚洲欧美成人| 一区二区三区国产| 欧美freesex交免费视频| 亚洲视频一区在线| 欧美久久久久久久久久| 在线观看国产精品网站| 久久精品国产清高在天天线| 99re热这里只有精品免费视频| 老司机aⅴ在线精品导航| 国产综合久久久久久鬼色| 亚洲欧美日韩在线| 夜夜嗨av色综合久久久综合网| 欧美国产激情二区三区| 亚洲欧洲日夜超级视频| 欧美韩日亚洲| 欧美日韩国产首页在线观看| 亚洲美女区一区|