關於內存在一塊其實我並非很想拿出來講,通常狀況下內存這一塊都是可優化的,能夠經過硬件資源或者調整一些系統或者應用系統的參數配置來進行優化。html
不少同僚問到了「內存泄漏」和「內存溢出」,其實這個在baidu上就有解釋。而咱們不少人常常會混淆了這兩個東西,在這裏我就簡單的引用一些資源說一下他們。
內存泄漏
內存泄漏也稱做「存儲滲漏」,用動態存儲分配函數動態開闢的空間,在使用完畢後未釋放,結果致使一直佔據該內存單元。直到程序結束。(其實說白了就是該內存空間使用完畢以後未回收)即所謂內存泄漏。
內存泄漏形象的比喻是「
操做系統可提供給全部進程的存儲空間正在被某個進程榨乾」,最終結果是程序運行時間越長,佔用存儲空間愈來愈多,最終用盡所有存儲空間,整個系統崩潰。因此「內存泄漏」是從操做系統的角度來看的。這裏的存儲空間並非指物理內存,而是指虛擬內存大小,這個虛擬內存大小取決於磁盤交換區設定的大小。由程序申請的一塊內存,若是沒有任何一個指針指向它,那麼這塊內存就泄漏。
表象
性能測試的時候發生內存泄漏的表象就是可用內存逐漸減小,一直不釋放。
內存泄漏分類
以發生的方式來分類,內存泄漏能夠分爲4類
常發性
發生內存泄漏的代碼會被屢次執行到,每次被執行的時候都會致使一塊內存泄漏。
偶發性
發生內存泄漏的代碼只有在某些特定環境或操做過程下才會發生。常發性和偶發性是相對的。對於特定的環境,偶發性的也許就變成了常發性的。因此測試環境和測試方法對檢測內存泄漏相當重要。
一次性
發生內存泄漏的代碼只會被執行一次,或者因爲算法上的缺陷,致使總會有一塊且僅一塊內存發生泄漏。好比,在類的構造函數中分配內存,在析構函數中卻沒有釋放該內存,因此內存泄漏只會發生一次。
隱式
程序在運行過程當中不停的分配內存,可是直到結束的時候才釋放內存。嚴格的說這裏並無發生內存泄漏,由於最終程序釋放了全部申請的內存。可是對於一個服務器程序,須要運行幾天、幾周甚至幾個月,不及時釋放內存也可能致使最終耗盡系統的全部內存。因此,咱們稱這類內存泄漏爲隱式內存泄漏。
危害
內存泄漏或者是說,資源耗盡後,系統會表現出什麼現象啊?
cpu資源耗盡:估計是機器沒有反應了,鍵盤,鼠標,以及網絡等等。在中了計算機病毒的設備上很是常見。
進程id耗盡:無法建立新的進程了,串口或者telnet都無法建立了。
硬盤耗盡: 機器要死了,交換內存無法用,日誌也無法用了,死是很正常的。
內存泄漏或者內存耗盡:新的鏈接沒法建立,free的內存比較少。發生內存泄漏的程序不少,可是要想產生必定的後果,就須要這個進程是無限循環的,是個服務進程。固然,內核也是無限循環的,因此,若是內核發生了內存泄漏,狀況就更加不妙。內存泄漏是一種很難定位和跟蹤的錯誤,目前還沒看到有什麼好用的工具(固然,用戶空間有一些工具,有靜態分析的,也會動態分析的,可是找內核的內存泄漏,沒有好的開源工具)。
內存泄漏和對象的引用計數有很大的關係,再加上c/c++都沒有自動的垃圾回收機制,若是沒有手動釋放內存,問題就會出現。若是要避免這個問題,仍是要從代碼上入手,良好的編碼習慣和規範,是避免錯誤的不二法門。
通常咱們常說的內存泄漏是指堆內存的泄漏。
堆內存是指程序從堆中分配的,大小任意的(內存塊的大小能夠在程序運行期決定),使用完後必須顯式釋放的內存。
應用程序通常使用malloc,realloc,new等函數從堆中分配到一塊內存,使用完後,程序必須負責相應的調用free或delete釋放該內存塊,不然,這塊內存就不能被再次使用,咱們就說這塊內存泄漏了。
部分檢測工具
1.ccmalloc-
Linux和Solaris下對C和C++程序的簡單的使用內存泄漏和malloc調試庫。
2.Dmalloc-Debug Malloc Library.
3.Electric Fence-Linux分發版中由Bruce Perens編寫的malloc()調試庫。
4.Leaky-Linux下檢測內存泄漏的程序。
5.LeakTracer-Linux、Solaris和HP-UX下跟蹤和分析C++程序中的內存泄漏。
6.MEMWATCH-由Johan Lindh編寫,是一個開放源代碼C語言內存錯誤檢測工具,主要是經過gcc的precessor來進行。
7.Valgrind-Debugging and profiling Linux programs, aiming at programs written in C and C++.
8.KCachegrind-A visualization tool for the profiling data generated by Cachegrind and Calltree.
9.IBM Rational PurifyPlus-幫助開發人員查明C/C++、託管.NET、Java和VB6代碼中的性能和可靠性錯誤。PurifyPlus 將內存錯誤和泄漏檢測、應用程序性能描述、代碼覆蓋分析等功能組合在一個單1、完整的工具包中。
10.ParasoftInsure++-針對C/C++應用的運行時錯誤自動檢測工具,它可以自動監測C/C++程序,發現其中存在着的內存破壞、內存泄漏、指針錯誤和I/O等錯誤。並經過使用一系列獨特的
技術(SCI技術和變異測試等),完全的檢查和測試咱們的代碼,精肯定位錯誤的準確位置並給出詳細的診斷信息。能做爲MicrosoftVisual C++的一個插件運行。
11.Compuware DevPartner for Visual C++ BoundsChecker Suite-爲C++開發者設計的運行錯誤檢測和調試工具軟件。做爲Microsoft Visual Studio和C++ 6.0的一個插件運行。
12.Electric Software GlowCode-包括內存泄漏檢查,code profiler,函數調用跟蹤等功能。給C++和.Net開發者提供完整的錯誤診斷,和運行時性能分析工具包。
13.Compuware DevPartner Java Edition-包含Java內存檢測,代碼覆蓋率測試,代碼性能測試,線程死鎖,分佈式應用等幾大功能模塊。
14.Quest JProbe-分析Java的內存泄漏。
15.ej-technologies JProfiler-一個全功能的Java剖析工具,專用於分析J2SE和J2EE應用程序。它把CPU、執行緒和內存的剖析組合在一個強大的應用中。
16.BEAJRockit-用來診斷Java內存泄漏並指出根本緣由,專門針對Intel平臺並獲得優化,能在Intel硬件上得到最高的性能。
內存溢出
(out of memory)通俗理解就是內存不夠,一般在運行大型軟件或遊戲時,軟件或遊戲所須要的內存遠遠超出了你主機內安裝的內存所承受大小,就叫內存溢出。此時軟件或遊戲就運行不了,系統會提示內存溢出,有時候會自動關閉軟件,重啓電腦或者軟件後釋放掉一部份內存又能夠正常運行該軟件或遊戲一段時間。
表象
常見out of memory 錯誤
產生緣由
內存溢出是指應用系統中存在沒法回收的內存或使用的內存過多,最終使得程序運行要用到的內存大於虛擬機能提供的最大內存。爲了解決Java中內存溢出問題,咱們首先必須瞭解Java是如何管理內存的。Java的內存管理就是對象的分配和釋放問題。在Java中,內存的分配是由程序完成的,而內存的釋放是由垃圾收集器(GarbageCollection,GC)完成的,程序員不須要經過調用GC函數來釋放內存,由於不一樣的JVM實現者可能使用不一樣的算法管理GC,有的是內存使用到達必定程度時,GC纔開始工做,也有定時執行的,有的是中斷式執行GC。但GC只能回收無用而且再也不被其它對象引用的那些對象所佔用的空間。Java的內存垃圾回收機制是從程序的主要運行對象開始檢查引用鏈,當遍歷一遍後發現沒有被引用的孤立對象就做爲垃圾回收。
引發內存溢出的緣由有不少種,常見的有如下幾種:
(1)內存中加載的數據量過於龐大,如一次從
數據庫取出過多數據;
(2)集合類中有對對象的引用,使用完後未清空,使得JVM不能回收;
(3)代碼中存在死循環或循環產生過多重複的對象實體;
(4)使用的第三方軟件中的BUG;
(5)啓動參數設定的太小;
解決方法
內存溢出雖然很棘手,但也有相應的解決辦法,能夠按照從易到難,一步步的解決。
第一步,就是修改JVM啓動參數,直接增長內存。這一點看上去彷佛很簡單,但很容易被忽略。JVM默承認以使用的內存爲64M,Tomcat默承認以使用的內存爲128MB,對於稍複雜一點的系統就會不夠用。在某項目中,就由於啓動參數使用的默認值,常常報「OutOfMemory」錯誤。所以,-Xms,-Xmx參數必定不要忘記加。
第二步,檢查錯誤日誌,查看「OutOfMemory」錯誤前是否有其它異常或錯誤。在一個項目中,使用兩個數據庫鏈接,其中專用於發送
短信的數據庫鏈接使用DBCP鏈接池管理,用戶爲不將短信發出,有意將數據庫鏈接用戶名改錯,使得日誌中有許多數據庫鏈接異常的日誌,一段時間後,就出現「OutOfMemory」錯誤。經分析,這是因爲DBCP鏈接池BUG引發的,數據庫鏈接不上後,沒有將鏈接釋放,最終使得DBCP報「OutOfMemory」錯誤。通過修改正確數據庫鏈接參數後,就沒有再出現內存溢出的錯誤。
查看日誌對於分析內存溢出是很是重要的,經過仔細查看日誌,分析內存溢出前作過哪些操做,能夠大體定位有問題的模塊。
第三步,安排有經驗的編程人員對代碼進行走查和分析,找出可能發生內存溢出的位置。重點排查如下幾點:
(1)
檢查代碼中是否有死循環或遞歸調用。
(2)
檢查是否有大循環重複產生新對象實體。
(3)
檢查對數據庫查詢中,是否有一次得到所有數據的查詢。通常來講,若是一次取十萬條記錄到內存,就可能引發內存溢出。這個問題比較隱蔽,在上線前,數據庫中數據較少,不容易出問題,上線後,數據庫中數據多了,一次查詢就有可能引發內存溢出。所以對於數據庫查詢儘可能採用分頁的方式查詢。
(4)
檢查List、MAP等集合對象是否有使用完後,未清除的問題。List、MAP等集合對象會始終存有對對象的引用,使得這些對象不能被GC回收。
第四步,使用內存查看工具動態查看內存使用狀況。某個項目上線後,每次系統啓動兩天後,就會出現內存溢出的錯誤。這種狀況通常是代碼中出現了緩慢的內存泄漏,用上面三個步驟解決不了,這就須要使用內存查看工具了。
內存查看工具備許多,比較有名的有:Optimizeit Profiler、JProbeProfiler、JinSight和Java1.5的Jconsole等。它們的基本工做原理大同小異,都是監測Java程序運行時全部對象的申請、釋放等動做,將內存管理的全部
信息進行統計、分析、可視化。開發人員能夠根據這些信息判斷程序是否有內存泄漏問題。通常來講,一個正常的系統在其啓動完成後其內存的佔用量是基本穩定的,而不該該是無限制的增加的。持續地觀察系統運行時使用的內存的大小,能夠看到在內存使用監控窗口中是基本規則的鋸齒形的圖線,若是內存的大小持續地增加,則說明系統存在內存泄漏問題。經過間隔一段時間取一次內存快照,而後對內存快照中對象的使用與引用等信息進行比對與分析,能夠找出是哪一個類的對象在泄漏。
經過以上四個步驟的分析與處理,基本能處理內存溢出的問題。固然,在這些過程當中也須要至關的經驗與敏感度,須要在實際的開發與調試過程當中不斷積累。
緩衝區溢出
爲了便於理解,咱們不妨打個比方。緩衝區溢出比如是將十磅的糖放進一個只能裝五磅的容器裏。一旦該容器放滿了,餘下的部分就溢出在櫃檯和地板上,弄得一團糟。因爲計算機程序的編寫者寫了一些編碼,可是這些編碼沒有對目的區域或緩衝區——五磅的容器——作適當的檢查,看它們是否夠大,可否徹底裝入新的內容——十磅的糖,結果可能形成緩衝區溢出的產生。若是打算被放進新地方的數據不適合,溢獲得處都是,該數據也會製造不少麻煩。可是,若是緩衝區僅僅溢出,這只是一個問題。到此時爲止,它尚未破壞性。當糖溢出時,櫃檯被蓋住。能夠把糖擦掉或用吸塵器吸走,還櫃檯原本面貌。與之相對的是,當緩衝區溢出時,過剩的信息覆蓋的是計算機內存中之前的內容。除非這些被覆蓋的內容被保存或可以恢復,不然就會永遠丟失。
在丟失的信息裏有可以被程序調用的子程序的列表信息,直到緩衝區溢出發生。另外,給那些子程序的信息——參數——也丟失了。這意味着程序不能獲得足夠的信息從子程序返回,以完成它的任務。就像一我的步行穿過沙漠。若是他依賴於他的足跡走回頭路,當沙暴來襲抹去了這些痕跡時,他將迷失在沙漠中。這個問題比程序僅僅迷失方向嚴重多了。入侵者用精心編寫的入侵代碼(一種惡意程序)使緩衝區溢出,而後告訴程序依據預設的方法處理緩衝區,而且執行。此時的程序已經徹底被入侵者操縱了。
入侵者常常改編現有的應用程序運行不一樣的程序。例如,一個入侵者能啓動一個新的程序,發送祕密文件(支票本記錄,口令文件,或財產清單)給入侵者的電子郵件。這就好像不只僅是沙暴吹了腳印,並且後來者也會踩出新的腳印,將咱們的迷路者領向不一樣的地方,他本身一無所知的地方。
緩衝處理
你屋子裏的門和窗戶越少,入侵者進入的方式就越少……
因爲緩衝區溢出是一個編程問題,因此只能經過修復被破壞的程序的代碼而解決問題。若是你沒有源代碼,從上面「堆棧溢出攻擊」的原理能夠看出,要防止此類攻擊,咱們能夠:
一、開放程序時仔細檢查溢出狀況,不容許數據溢出緩衝區。因爲編程和編程語言的緣由,這很是困難,並且不適合大量已經在使用的程序;
二、使用檢查堆棧溢出的編譯器或者在程序中加入某些記號,以便程序運行時確認禁止
黑客有意形成的溢出。問題是沒法針對已有程序,對新程序來說,須要修改編譯器;
三、常常檢查你的操做系統和應用程序提供商的站點,一旦發現他們提供的補丁程序,就立刻下載而且應用在系統上,這是最好的方法。可是系統管理員總要比攻擊者慢一步,若是這個有問題的軟件是可選的,甚至是臨時的,把它從你的系統中刪除。舉另一個例子,你屋子裏的門和窗戶越少,入侵者進入的方式就越少。
扯遠了,這些是安全性測試方面的內容。不過性能測試方面有時候也得注意這些內容。性能測試的時候若是應用程序不報錯,而且系統的可用內存不是在不斷減小,就能夠認爲內存正常。
本文轉自: http://www.51testing.com/html/80/n-3721680.html