從記憶體分配談起

2021-09-24 09:47:59 字數 2066 閱讀 3873

來自:

言歸正傳,大家在平時的開發過程中,發生記憶體錯誤是件非常麻煩的事情,編譯器不能自動發現這些錯誤,只有在程式執行時才會**捉到,而這些錯誤大多沒有明顯的症狀,時隱時現,來無影,去無蹤,在面對這些問題時,要想做到望聞診切,然後藥到病除,不如,讓我們從頭理一理記憶體的那些個事兒。

記憶體是cpu和硬碟進行溝通的橋梁,cpu是處理器,是大腦和核心,記憶體和硬碟是儲存器,受cpu的指揮。

cpu工作的時候:

1:需要從儲存器把資料取出來。

2:進行運算,要不停的對儲存器讀寫。

3:計算出結果,再返回到儲存器進行儲存。

如果硬碟夠快的話,就不需要記憶體了,但硬碟太慢了,所以由硬碟擔任1和3的工作,由記憶體分擔硬碟2的工作,所以說記憶體就相當於硬碟和cpu之間的中轉站。

而我們一般寫的程式經過預處理(主要是一些**文字的替換工作)、編譯(生成彙編**)、鏈結(多個目標檔案,庫拼合的過程)、生成二進位制的可執行檔案儲存在硬碟中,當執行可執行程式時,作業系統會把執行檔案從硬碟拷貝到記憶體,之後cpu就從記憶體中讀取執行檔案的命令,cpu不斷的一條指令一條指令的讀取和執行。

記憶體一般包括唯讀儲存器(rom),隨機儲存器(ram),以及快取記憶體(cache)。rom是唯讀儲存器,一般用於存放計算機的基本程式和資料,如bios,cpu對rom是唯讀不存。

而我們開發中提到的記憶體指的是計算機的隨機儲存器(ram),乙個由c/c++編譯的程式占用的記憶體分為以下幾個部分: 

(1)全域性區(靜態區):內存在程式編譯時就已經分配好,這塊內存在程式的整個執行期間都存在。速度快、不容易出錯,因為有系統會善後。例如全域性變數,static變數等。

(2)棧區:由程式自動向作業系統申請分配以及**,速度快,使用方便,但程式設計師無法控制。若分配失敗,則提示棧溢位錯誤。在執行函式時,函式內區域性變數的儲存單元都在棧上建立,函式執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。棧區向位址減小的方向增長。

(3)堆區:即動態記憶體分配。程式在執行的時候用malloc或new申請任意大小的記憶體,程式設計師自己負責在何時用free或delete釋放記憶體。動態記憶體的生存期由程式設計師決定,使用非常靈活。如果在堆上分配了空間,就有責任**它,否則執行的程式會出現記憶體洩漏,另外頻繁地分配和釋放不同大小的堆空間將會產生堆內碎塊。注意與資料結構中的堆不是一回事兒。堆區是向高位址擴充套件的,是不連續的。

(4)文字常量區:存放常量字串的記憶體,程式結束後由系統釋放。

(5)程式**區:存放函式體的二進位制**。

環境變數和命令列引數

棧區堆區

未初始化的全域性區(靜態區)

初始化的全域性區(靜態區)

**段了解了記憶體分配的機理後,讓我們看看常見的記憶體錯誤以及有哪些對策:

1、在使用指標時,記憶體分配還沒成功。

程式設計新手常犯這種錯誤,因為他們沒有意識到記憶體分配會不成功。常用解決辦法是,在使用記憶體之前檢查指標是否為null。如果指標p是函式的引數,那麼在函式的入口處用assert(p!=null)進行檢查。如果是用malloc或new來申請記憶體,應該用if(p==null) 或if(p!=null)進行防錯處理。

2、記憶體分配雖然成功,但是尚未初始化就引用它。

犯這種錯誤主要有兩個起因:一是沒有初始化的觀念;二是誤以為記憶體的預設初值全為零,導致引用初值錯誤(例如陣列)。

記憶體的預設初值究竟是什麼並沒有統一的標準,儘管有些時候為零值,我們寧可信其無不可信其有。所以無論用何種方式建立陣列,都別忘了賦初值,即便是賦零值也不可省略,不要嫌麻煩。

3、 記憶體分配成功並且已經初始化,但操作越過了記憶體的邊界。

例如在使用陣列時經常發生下標「多1」或者「少1」的操作。特別是在for迴圈語句中,迴圈次數很容易搞錯,導致陣列操作越界。

附:malloc和new的區別:

(1)new、delete是操作符,可以過載,只能在c++中使用。 

(2)malloc、free是函式,可以覆蓋,c、c++中都可以使用。 

(3)new 可以呼叫物件的建構函式,對應的delete呼叫相應的析構函式。 

(4)malloc僅僅分配記憶體,free僅僅**記憶體,並不執行構造和析構函式 

(5)new、delete返回的是某種資料型別指標,malloc、free返回的是void指標。

從生活談起

你有了目標,你開始了幾點一線的生活。慢慢的你發現,活著,就是為了掙大錢。可是畢竟人生不是一帆風順,你找不到喜歡的工作,遇不到志同道合的同事,這時候你開始無措,想回到小時候,想找人訴苦,甚至你還想過自殺。慶幸的是,你發現,你還有個溫暖的家。有的人一生真的很不容易,但是他們卻活的很幸福,他們不奢求錦衣玉...

從機器學習談起

在本篇文章中,我將對機器學習做個概要的介紹。本文的目的是能讓即便完全不了解機器學習的人也能了解機器學習,並且上手相關的實踐。這篇文件也算是easypr開發的番外篇,從這裡開始,必須對機器學習了解才能進一步介紹easypr的核心。當然,本文也面對一般讀者,不會對閱讀有相關的前提要求。在進入正題前,我想...

從西遊記談起

西遊記這個電視劇集,固然拍的很成功,我還記得小時候看西遊記,像過年似的,那種高興和喜悅,讓我們這些小孩子死扛著不肯離開電視機,當時我家裡並沒有電視機,我們都是在別人家裡看的,趕都趕不走.印象最深的就是乙個人家把電視機擺到了街頭的空地上,周圍的鄰居,無論大人或者小孩,都圍著看了夠,那集演的是 女兒國 ...