1.函數代碼存放在程式碼片段。聲明的類如果從未使用,則在編譯時間,會最佳化掉,其成員函數不佔程式碼片段空間。
全域變數或靜態變數,放在資料區段,
局部變數放在棧中,
用new產生的對象放在堆中,
記憶體分為4段,棧區,堆區,代碼區,全域變數區
BSS段:BSS段(bss segment)通常是指用來存放程式中未初始化的全域變數的一塊記憶體地區。
BSS是英文Block Started by Symbol的簡稱。BSS段屬於靜態記憶體配置。
2.程式碼片段、資料區段、棧是CPU層級的邏輯概念,堆是語言層級的邏輯概念
3.還有一個常量區,其中的內容不許修改。
常見的 char *p = "hello"; 這裡面的"hello"就儲存在常量區
4.如1樓所說,把程式碼片段、資料區段,棧,堆這些並列在一起不太合適
程式碼片段、資料區段、堆棧段,這是一個概念
堆、棧、全域區、常量區,這是另一個概念
5.STACK(棧)臨時局部
HEAP(堆)動態
RW(讀寫)全域
RO(唯讀)代碼
Char* s=”Hello,World”; S中“H”存放在記憶體RO中且不能修改。
6.CPU寄存器:CPU寄存器,其實就是來控制碼段和資料區段的指令及資料讀取的地方,當然,CPU也有自己存放資料的地方,那就是通用寄存器裡的資料寄存器,通常是EDX寄存器,C語言裡有個register,就是把資料放在這個寄存器裡,這樣讀取資料就相當的快了,因為不用去記憶體找,就省去了定址和傳送資料的時間開銷。他還有一些寄存器是用來指示當前程式碼片段的位置、資料區段的位置、堆棧段的位置等等(注意這裡存放的只是相應的代碼或資料在記憶體中的地址,並不是實際的值,然後根據這個地址,通過地址匯流排和資料匯流排,去記憶體中擷取相應的值),不然在執行代碼的時候,指令和資料從哪取呢?呵呵。。。他裡面還有標誌寄存器,用來標識一些狀態位,比如標識算術溢位呀等等。。。。。
————————————————————————————————————————————————————————————————
記憶體分段(筆記)
在馮諾依曼的體繫結構中必須有:程式碼片段,堆棧段,資料區段
因為馮氏結構,本質就是取址,執行的過程
編譯器和系統在為變數分配是從高地址開始分配的.
全域變數和函數參數在記憶體中的儲存是由低地值到高地址的.
函數參數為什麼會放到堆區呢?
這是因為我們的函數是在程式運行中進行動態調用的.
在函數的編譯階段根本無法確定他會調用幾次,會需要多少記憶體.
即使可以確定那時候就為變數分配好記憶體著實也是一種浪費。
所以編譯器為函數參數選擇動態分配..即在每次調用函數時才為它動態進行分配空間.
####################################################
記憶體分為4段,棧區,堆區,代碼區,全域變數區
BSS段:BSS段(bss segment)通常是指用來存放程式中未初始化的全域變數的一塊記憶體地區。
BSS是英文Block Started by Symbol的簡稱。BSS段屬於靜態記憶體配置。
資料區段:資料區段(data segment)通常是指用來存放程式中已初始化的全域變數的一塊記憶體地區。資料區段屬於靜態記憶體配置。
程式碼片段:程式碼片段(code segment/text segment)通常是指用來存放程式執行代碼的一塊記憶體地區。
這部分地區的大小在程式運行前就已經確定,並且記憶體地區通常屬於唯讀, 某些架構也允許程式碼片段為可寫,即允許修改程式。
在程式碼片段中,也有可能包含一些唯讀常數變數,例如字串常量等。程式碼片段是存放了程式碼的資料,
假如機器中有數個進程運行相同的一個程式,那麼它們就可以使用同一個程式碼片段。
堆(heap):堆是用於存放進程運行中被動態分配的記憶體段,它的大小並不固定,
可動態擴張或縮減。當進程調用malloc等函數分配記憶體時,新分配的記憶體就被動態添加到堆上(堆被擴張);
當利用free等函數釋放記憶體時,被釋放的記憶體從堆中被剔除(堆被縮減)
棧(stack):棧又稱堆棧, 是使用者存放程式臨時建立的局部變數,
也就是說我們函數括弧“{}”中定義的變數(但不包括static聲明的變數,static意味著在資料區段中存放變數)。
除此以外,在函數被調用時,其參數也會被壓入發起調用的進程棧中,並且待到調用結束後,函數的傳回值也會被存放回棧中。
由於棧的先進先出特點,所以棧特別方便用來儲存/恢複調用現場。從這個意義上講,我們可以把堆棧看成一個寄存、交換臨時資料的記憶體區。
(1)記憶體分段和記憶體分頁一樣都是一種記憶體管理技術,分段:許可權保護,分頁:虛擬記憶體.
(2)分段後,程式員可以定義自己的段,各段有獨立的地址空間,象進程的地址空間互相獨立一樣.
(3)同一個類的執行個體分配在一個段中,只有該類的方法可以訪問,如果其他類的方法去訪問,會因為段保護而出錯.可以從硬體上實作類別的資料保護和隱藏
####################################################################
分段好處:
cpu中的段寄存器-------段址(base)和位移值的上限(limit)。
段址:有效地址 中,如果有效地址大於limit,便會引發異常。這樣就可以限制程式不能範圍當前段外的資料,不能訪問其他程式的資料。
物件導向的好處:對象就是一塊連續的記憶體中的資料
寄存器是特殊形式的記憶體,嵌入到處理器內部。
每個進程需要訪問記憶體中屬於自身的地區,因此,可將記憶體劃分成小的段,按需分發給進程。
寄存器用來儲存和跟蹤進程當前維護的段。位移寄存器(Offset Registers)用來跟蹤關鍵的資料放在段中的位置。
在進程被載入記憶體中時,基本上被分裂成許多小的節(section)。我們比較關注的是6個主要的節:
(1) .text 節
.text 節基本上相當於二進位可執行檔的.text部分,它包含了完成程式任務的機器指令。
該節號為唯讀,如果發生寫操作,會造成segmentation fault。在進程最初被載入到記憶體中開始,該節的大小就被固定。
(2).data 節
.data節用來儲存初始化過的變數,如:int a =0 ; 該節的大小在運行時固定的。
(3).bss 節
棧下節(below stack section ,即.bss)用來儲存為初始化的變數,如:int a; 該節的大小在運行時固定的。
(4) 堆節
堆節(heap section)用來儲存動態分配的變數,位置從記憶體的低地址向高地址增長。記憶體的分配和釋放通過malloc() 和 free() 函數控制。
(5) 棧節
棧節(stack section)用來跟蹤函數調用(可能是遞迴的),在大多數系統上從記憶體的高地址向低地址增長。
同時,棧這種增長方式,導致了緩衝區溢位的可能性。
(6)環境/參數節
環境/參數節(environment/arguments section)用來儲存系統內容變數的一份複製檔案,
進程在運行時可能需要。例如,運行中的進程,可以通過環境變數來訪問路徑、shell 名稱、主機名稱等資訊。
該節是可寫的,因此在格式串(format string)和緩衝區溢位(buffer overflow)攻擊中都可以使用該節。
另外,命令列參數也保持在該地區中。
################################################################################
以win32程式為例。
程式執行時,作業系統將exe檔案對應入記憶體。exe檔案格式為頭資料和各段資料群組成。
頭資料說明了exe檔案的屬性和執行環境,段資料又分為資料區段,程式碼片段,資源段等,段的多少和位置由頭資料說明。
也就是說,不僅僅只是程式碼片段和資料區段。這些段由不同的編譯環境和編譯參數控制,由編譯器自動產生exe的段和檔案格式。
當作業系統執行exe時,會動態建立堆棧段,它是動態,並且屬於作業系統執行環境。
也就是說,程式在記憶體的映射一個為exe檔案對應,包括資料區段、程式碼片段等它是不變的。
另一個為堆棧段,它是隨程式運行動態改變的。
1、編譯器把原始碼轉化成分立的目標代碼(.o或者.obj)檔案,這些檔案中的代碼已經是可執行檔機器碼或者是中間代碼。
但是其中變數等事物的地址只是一些符號。
2、接下來是通過連結器處理這些目標代碼,主要目的就是把分立的目標代碼串連成一份完整的可執行代碼,
並將其中的地址符號換成相對位址。如果這時候產生錯誤,我們就可以得到一份地址符號列表,而不是變數列表。
3、執行程式的時候作業系統分配足夠的記憶體空間,建立好系統支撐結構後把二進位可執行代碼讀入記憶體中。
在讀入過程中記憶體首址就成了程式的“絕對位址”(實際上還是相對位址,不過是作業系統裡的相對位址了)。
於是絕對位址+相對位址(就是位移量)就得到了變數的地址。
因此,CS的值是由系統填入的,而其它S寄存器的值則是根據程式碼中附加的資訊計算後得到的。