从更底层研究C\C++动态内存分配
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
以前在學(xué)C++ 的時(shí)候,一直不懂:動(dòng)態(tài)內(nèi)存分配的本質(zhì),或者更加深入到底層的意義.雖然說,動(dòng)態(tài)內(nèi)存分配就是,隨機(jī)在內(nèi)存中分配一個(gè)地址,但是這句話包含的內(nèi)容實(shí)在太多了,不去理解底層的話,無論如何也僅僅停留在表面階段,永遠(yuǎn)提高不了.今天下午,突然看到好久以前的QT5,基本半年沒研究過了,還是以前沒事干瞎做播放器的時(shí)候安裝的,于是來了興趣,想玩玩看.
但是,我遇到了一個(gè)問題,就是始終不懂QT框架這么設(shè)計(jì)的核心,或者從操作系統(tǒng)級(jí)別來講,它為什么提供這樣的方式?
請(qǐng)看代碼,最簡(jiǎn)單的默認(rèn)項(xiàng)目;
#include <QApplication> #include <MainWindow>int main(int argc, char *argv[]){QApplication a(argc, argv);MainWindow w;w.show();return a.exec();}這是一個(gè)最簡(jiǎn)單的程序:就是顯示一個(gè)窗口,恐怕很多人已經(jīng)習(xí)以為常了吧.
但是,我此時(shí)有問題要問:
#include <QApplication> #include <MainWindow>int main(int argc, char *argv[]){QApplication a(argc, argv);MainWindow *w=new MainWindow;w->show();return a.exec();}這個(gè)程序運(yùn)行起來,和上面是完全一樣的,但是請(qǐng)問:有什么問題?也許很多人一口就說,沒問題啊,不就是和上面一樣嗎?
細(xì)心的人發(fā)現(xiàn)有不同
:
然后,我們?cè)诳匆幌逻@個(gè)代碼:
#include <QApplication> #include <QPushButton> #include <mainwindow.h> #include <QDebug> int main(int argc, char *argv[]) {QApplication app(argc, argv);QPushButton bt1;QPushButton *bt2=new QPushButton;MainWindow w1;MainWindow *w2=new MainWindow;qDebug() << "bt1:%d " << &bt1;qDebug() << "bt2:%d " << bt2;qDebug() << "w1:%d " << &w1;qDebug() << "w2:%d " << w2;return app.exec(); }我們來測(cè)試一下內(nèi)存分配結(jié)果:
注意:系統(tǒng)分配法和動(dòng)態(tài)分配法地址長(zhǎng)度不一樣!
一個(gè)用了直接定義法,一個(gè)用了指針寫法,問題就是:每個(gè)人都能說:后面的是動(dòng)態(tài)內(nèi)存分配,前面的是操作系統(tǒng)分配.還有呢?動(dòng)態(tài)內(nèi)存分配究竟怎么個(gè)分配法?
或許很多人學(xué)C++的時(shí)候,也是面對(duì)這兩種寫法 很懵逼,貌似一樣吧,但是本質(zhì)又不一樣.一直在表面逗留,而深入不到本質(zhì)去.
我這里,從更加底層開始分析.我們首先從芯片結(jié)構(gòu)來說起.有人覺得C++怎么會(huì)和芯片結(jié)構(gòu)有關(guān)系?別忘了,C++繼承了C的所有.
好了,開始說芯片:我們從最簡(jiǎn)單的51單片機(jī)說起.
下面是百科:
8051是MCS-51系列單片機(jī)的典型產(chǎn)品,我們以這一代表性的機(jī)型進(jìn)行系統(tǒng)的講解。
8051單片機(jī)包含中央處理器、程序存儲(chǔ)器(ROM)、數(shù)據(jù)存儲(chǔ)器(RAM)、定時(shí)/計(jì)數(shù)器、并行接口、串行接口和中斷系統(tǒng)等幾大單元及數(shù)據(jù)總線、地址總線和控制總線等三大總線,現(xiàn)在我們分別加以說明:
· 中央處理器:
中央處理器(CPU)是整個(gè)單片機(jī)的核心部件,是8位數(shù)據(jù)寬度的處理器,能處理8位二進(jìn)制數(shù)據(jù)或代碼,CPU負(fù)責(zé)控制、指揮和調(diào)度整個(gè)單元系統(tǒng)協(xié)調(diào)的工作,完成運(yùn)算和控制輸入輸出功能等操作。
· 數(shù)據(jù)存儲(chǔ)器(RAM):
8051內(nèi)部有128個(gè)8位用戶數(shù)據(jù)存儲(chǔ)單元和128個(gè)專用寄存器單元,它們是統(tǒng)一編址的,專用寄存器只能用于存放控制指令數(shù)據(jù),用戶只能訪問,而不能用于存放用戶數(shù)據(jù),所以,用戶能使用的的RAM只有128個(gè),可存放讀寫的數(shù)據(jù),運(yùn)算的中間結(jié)果或用戶定義的字型表。
· 程序存儲(chǔ)器(ROM):
8051共有4096個(gè)8位掩膜ROM,用于存放用戶程序,原始數(shù)據(jù)或表格。
· 定時(shí)/計(jì)數(shù)器(ROM):
8051有兩個(gè)16位的可編程定時(shí)/計(jì)數(shù)器,以實(shí)現(xiàn)定時(shí)或計(jì)數(shù)產(chǎn)生中斷用于控制程序轉(zhuǎn)向。
· 并行輸入輸出(I/O)口:
8051共有4組8位I/O口(P0、 P1、P2或P3),用于對(duì)外部數(shù)據(jù)的傳輸。
· 全雙工串行口:
8051內(nèi)置一個(gè)全雙工串行通信口,用于與其它設(shè)備間的串行數(shù)據(jù)傳送,該串行口既可以用作異步通信收發(fā)器,也可以當(dāng)同步移位器使用。
· 中斷系統(tǒng):
8051具備較完善的中斷功能,有兩個(gè)外中斷、兩個(gè)定時(shí)/計(jì)數(shù)器中斷和一個(gè)串行中斷,可滿足不同的控制要求,并具有2級(jí)的優(yōu)先級(jí)別選擇。
· 時(shí)鐘電路:
8051內(nèi)置最高頻率達(dá)12MHz的時(shí)鐘電路,用于產(chǎn)生整個(gè)單片機(jī)運(yùn)行的脈沖時(shí)序,但8051單片機(jī)需外置振蕩電容。
· 時(shí)鐘電路:
8051內(nèi)置最高頻率達(dá)12MHz的時(shí)鐘電路,用于產(chǎn)生整個(gè)單片機(jī)運(yùn)行的脈沖時(shí)序,但8051單片機(jī)需外置振蕩電容。
單片機(jī)的結(jié)構(gòu)有兩種類型,一種是程序存儲(chǔ)器和數(shù)據(jù)存儲(chǔ)器分開的形式,即哈佛(Harvard)結(jié)構(gòu),另一種是采用通用計(jì)算機(jī)廣泛使用的程序存儲(chǔ)器與數(shù)據(jù)存儲(chǔ)器合二為一的結(jié)構(gòu),即普林斯頓(Princeton)結(jié)構(gòu)。INTEL的MCS-51系列單片機(jī)采用的是哈佛結(jié)構(gòu)的形式,而后續(xù)產(chǎn)品16位的MCS-96系列單片機(jī)則采用普林斯頓結(jié)構(gòu)。
注意:重點(diǎn)在這里.
數(shù)據(jù)存儲(chǔ)器?程序存儲(chǔ)器?這是什么?和C++動(dòng)態(tài)呢誒村分配又有什么關(guān)系?
那我們就來抓一下頭緒.
下面是百科,關(guān)于程序區(qū)和數(shù)據(jù)區(qū):
C語言可執(zhí)行代碼結(jié)構(gòu)
| ?名稱 | 內(nèi)容 |
| 代碼段 | ?可執(zhí)行代碼、字符串常量 |
| 數(shù)據(jù)段 | ?已初始化全局變量、已初始化全局靜態(tài)變量、局部靜態(tài)變量、常量數(shù)據(jù) |
| BSS段 | ?未初始化全局變量,未初始化全局靜態(tài)變量 |
| 棧 | ?局部變量、函數(shù)參數(shù) |
| 堆 | ?動(dòng)態(tài)內(nèi)存分配 |
??????? 一般情況下,一個(gè)可執(zhí)行二進(jìn)制程序(更確切的說,在Linux操作系統(tǒng)下為一個(gè)進(jìn)程單元,在UC/OSII中被稱為任務(wù))在存儲(chǔ)(沒有調(diào)入到內(nèi)存運(yùn)行)時(shí)擁有3個(gè)部分,分別是代碼段(text)、數(shù)據(jù)段(data)和BSS段。這3個(gè)部分一起組成了該可執(zhí)行程序的文件。
??????? (1)代碼段(text segment):存放CPU執(zhí)行的機(jī)器指令。通常代碼段是可共享的,這使得需要頻繁被執(zhí)行的程序只需要在內(nèi)存中擁有一份拷貝即可。代碼段也通常是只讀的,這樣可以防止其他程序意外地修改其指令。另外,代碼段還規(guī)劃了局部數(shù)據(jù)所申請(qǐng)的內(nèi)存空間信息。
??????? 代碼段(code segment/text segment)通常是指用來存放程序執(zhí)行代碼的一塊內(nèi)存區(qū)域。這部分區(qū)域的大小在程序運(yùn)行前就已經(jīng)確定,并且內(nèi)存區(qū)域通常屬于只讀, 某些架構(gòu)也允許代碼段為可寫,即允許修改程序。在代碼段中,也有可能包含一些只讀的常數(shù)變量,例如字符串常量等。
??????? (2)數(shù)據(jù)段(data segment):或稱全局初始化數(shù)據(jù)段/靜態(tài)數(shù)據(jù)段(initialized data segment/data segment)。該段包含了在程序中明確被初始化的全局變量、靜態(tài)變量(包括全局靜態(tài)變量和局部靜態(tài)變量)和常量數(shù)據(jù)。
??????? (3)未初始化數(shù)據(jù)段:亦稱BSS(Block Started by Symbol)。該段存入的是全局未初始化變量、靜態(tài)未初始化變量。
??????? 而當(dāng)程序被加載到內(nèi)存單元時(shí),則需要另外兩個(gè)域:堆域和棧域。圖1-1所示為可執(zhí)行代碼存儲(chǔ)態(tài)和運(yùn)行態(tài)的結(jié)構(gòu)對(duì)照?qǐng)D。一個(gè)正在運(yùn)行的C程序占用的內(nèi)存區(qū)域分為代碼段、初始化數(shù)據(jù)段、未初始化數(shù)據(jù)段(BSS)、堆、棧5個(gè)部分。
?
?
圖1-1? C語言可執(zhí)行代碼結(jié)構(gòu)
????? (4)棧段(stack):存放函數(shù)的參數(shù)值、局部變量的值,以及在進(jìn)行任務(wù)切換時(shí)存放當(dāng)前任務(wù)的上下文內(nèi)容。
????? (5)堆段(heap):用于動(dòng)態(tài)內(nèi)存分配,即使用malloc/free系列函數(shù)來管理的內(nèi)存空間。
???? 在將應(yīng)用程序加載到內(nèi)存空間執(zhí)行時(shí),操作系統(tǒng)負(fù)責(zé)代碼段、數(shù)據(jù)段和BSS段的加載,并將在內(nèi)存中為這些段分配空間。棧段亦由操作系統(tǒng)分配和管理,而不需要程序員顯示地管理;堆段由程序員自己管理,即顯示地申請(qǐng)和釋放空間。
??? 另外,可執(zhí)行程序在運(yùn)行時(shí)具有相應(yīng)的程序?qū)傩浴T谟胁僮飨到y(tǒng)支持時(shí),這些屬性頁由操作系統(tǒng)管理和維護(hù)。
轉(zhuǎn)載于:https://my.oschina.net/xiaoershaoye/blog/1537274
總結(jié)
以上是生活随笔為你收集整理的从更底层研究C\C++动态内存分配的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 9.13作业
- 下一篇: FreeRTOS(三)——资源管理