標籤:style blog color 使用 問題 linux
愛鑽牛角尖的毛病又來了。僅僅是因為以前的一個c語言free記憶體報錯。
我們知道,malloc分配的記憶體是從堆裡獲得的,而堆是由作業系統維護的,也就是說,在沒有malloc前,記憶體空間是不屬於該進程空間的,malloc函數務必調用了作業系統的系統函數(參考前邊linux記憶體管理heap篇可知,是brk和sbrk)。也就是說,brk和sbrk是linux的系統調用,在沒有linux系統之前,是沒有這兩個函數的。比如我之前寫過的DSP裸機驅動,雖然也是用的c語言,但是是不可能有brk和sbrk及malloc函數的。brk和sbrk函數向作業系統申請記憶體時,作業系統會打破該進程原有的虛擬位址空間(準確的說是增加虛擬位址空間),作業系統負責維護新增的虛擬位址和物理地址的映射(需要硬體MMU等的支援,這裡暫不討論)這時候,申請過的對空間就和該進程空間融合到一起了。記憶體使用量完畢後,調用free函數釋放記憶體時,其實沒有被真正的釋放,作業系統維護堆記憶體的方式是通過chunks,free時僅僅是把chunks標記為可用狀態(參考上一篇部落格),作業系統維護這些chunks是用了一個結構體:
struct mem_control_block { int is_available; //這是一個標記? int size; //這是實際空間的大小 };
當我們free時,實質是:
void free(void *ptr) { struct mem_control_block *free; free = ptr - sizeof(struct mem_control_block); free->is_available = 1; return; }
當該進程下一次通過malloc申請記憶體時,作業系統首先會檢查該進程空間的chunks,如果有chunks可用,就直接使用,否則才會調用brk和sbrk系統調用來重新分配記憶體,這樣做的好處時,可以減少不必要的系統調用,提高效率,因為系統調用是很耗系統資源的。
由此,再加上我做DSP裸機驅動的經驗,可以大概探測出整個電腦硬體和作業系統及編譯器之間的聯絡:硬體支援二進位指令,通過二進位指令開發出一種程式,這種程式可以翻譯我敲進去的會變得代碼,這個程式就是彙編編譯器。通過組合語言開發一種程式,這種程式可以把c源碼翻譯成彙編,再交由彙編編譯器翻譯成為二進位,這種程式就是c語言編譯器。通過c語言編譯器開發一種程式,這種程式可以對電腦硬體進行管理,並且可以有多進程的功能……這種程式就是電腦作業系統比如linux。開發linux時可能也是有一個c語言的主函數,但是不會有brk和sbrk、malloc、free、printf等等這些函數,因為這些函數都是起作用在linux之上的。那為什麼我們在linux系統之寫c源碼時,就可以使用printf、brk、malloc等等這些函數了呢?開發linux系統時不能使用,現在為什麼就能使用了呢?問這個問題的人還是混淆了編譯器和庫(也就是寫好的調用,寫好的程式)的概念。linux作業系統上的編譯器還是開發那個開發linux系統時的編譯器,功能一點都沒有增加,但是多了許多庫可以調用。就好比,一個人來到一個荒漠,他通過自己的能力構建了一個豪華別墅,並且把別墅預留了很多接線口,水龍頭等,雖然說,人還是那個人,還是只有能的功能,但是這時候他已經可以通過。