運行過程中程序中的變數存儲在哪?
在我理解中CPU只能訪問內存中的信息,當需要與外界交互的時候需要CPU操縱外設將信息載入內存,不知道我的理解有沒有問題?那麼,當一個程序運行的時候,系統會將源程序載入內存,CPU通過訪問內存獲取程序和資源,那程序在運行計算流程的時候,程序變數存儲在哪?是在CPU緩存么?
先將程序變數這個概念,細分成兩部分。一是變數本身的名字,二是變數引用的數據。這樣問題就會轉換成,變數的名字存儲在那裡?變數引用的數據存儲在哪裡?
在 C 語言,變數名字又分成內部名字和外部名字。名字編譯後會被映射成數據的地址(可以是絕對地址或者偏移地址),如何通過地址來訪問數據,本身就是代碼的一部分。而外部變數的地址,在編譯的時候還不能完全確定,就先空著,等鏈接的時候再進行回填。為支持鏈接,外部變數的名字經過 name mangling 後需要存儲在符號表當中。
C 語言寫的程序,在運行時是不需要變數名字的,已經映射成數據的地址,成為代碼的一部分了。
那變數表示的數據存儲在哪裡?存儲在內存當中啊。更準確地說是存儲在虛擬內存中。
圖所示的就是 32 位 Linux 程序在運行時的虛擬地址空間。程序數據可以存儲在棧當中,也可以存儲在堆當中。另外全局數據(對應於全局變數),一開始就分配好的,空間大小是固定的。而棧空間、和堆空間的大小是會變化的,見箭頭方向。
程序中用到的所有地址,都不是真實的內存地址,只是虛擬內存地址。程序用到虛擬內存,分成一頁頁,比如每頁是 4K。有些頁確實存儲在真實的內存當中,但有些頁存儲在磁碟當中,有些頁就單純空著。操作系統和硬體會將虛擬內存映射成真實的內存,具體的程序不用關心。當程序訪問的虛擬內存頁並不在真實內存中時,就會觸發缺頁中斷,操作系統這時就將對應的頁載入到真實內存,再重新訪問。假如這時真實內存滿了,就將太久沒有使用的頁轉出到磁碟當中。程序就認為自己獨立擁有了 4G 虛擬地址空間。
程序啟動時,也不需要真的將信息載入到真實的內存,而只需要建立映射。這樣當程序運行時,就產生缺頁中斷。需要用到的信息就很自然載入到真實內存當中,而沒有真正用到的信息可以一直保留在磁碟當中。因此就算真實內存只有 1G,也可以運行 4G 的程序。
更具體的問題很難一下子就完全明白,再看看書吧,慢慢就會知道的了。知識是網狀的,而不是線性的,沒有可能從頭看到尾就一下子全明白,也不用一下子就全部弄清楚。
簡單說,所有變數都是放在內存中,運算的時候根據指令的需要部分變數會首先被載入到寄存器中,然後進行運算,運算結果根據指令的需要保存到內存中。從內存中載入變數到寄存器的過程中,如果有cache的話,cpu會首先根據變數的地址去查詢cache中是否有此變數,若有則表示命中,若無則去內存中取自己訪問這個變數,並將此變數所在的塊一起讀到cache中保存(注意,不僅僅讀該變數),具體情況根據cpu中實現的cache讀寫策略的不同而定。
另外,需要注意的是程序也是保存在內存中,只是根據連接器的鏈接腳本里的規則,程序和數據是從不同的地址開始的,具體可以查看《程序員的自我修養》和《深入理解計算機系統》,或者找到gnu binutils去hacking裡面的鏈接腳本ldscript。
程序的起始地址會被保存在pc中。而對於數據來說較為複雜一些,在內存中會分成好幾個段,因為數據還分為局部變數(保存在棧里stack),全局變數靜態變數(.bss段中)和常量(保存在.bss段中),malloc或者new出來的東西放在堆上(heap)。因此,對於不同的架構對於這些段的訪問方式也不同,某些架構會提供所謂的數據指針(Data Pointer,DP)去訪問這些數據,還有一部分直接通過指令去訪問這些地址。
上面說的這些都是在最簡單的系統中是這樣處理的。如果有硬碟,並且支持較為複雜操作系統的情況下(以x86,linux為例),操作系統需要通過mmu來進行內存管理,常見的段、頁調度策略就起作用了,將任務或者應用多包含的程序和數據在內存和硬碟之間調入調出。
我說的也不完整,建議仔細閱讀《程序員的自我修養》和《深入理解操作系統》,並找個gcc編譯器反彙編對照一下,便於理解,沒什麼難的。csapp會告訴你答案
操作數放在寄存器里,寄存器從cache拿,cache從內存拿,但是本質上都是從內存讀寫,寄存器和cache只是為了平衡計算速度和訪存速度,具體就是利用程序的局部性,構建多層存儲結構,從cache到內存越來越大越來越慢。也有一種數據流體系結構,數據不需要暫存,在指令之間流動就好
推薦閱讀:
※C++中已經有面向對象的概念,那struct還有啥存在的意圖?
※Python模塊如何安裝 並確認模塊已經安裝好?
※在編程中有沒有巧妙運用數學知識解決過問題?
※如何看待波格契夫2015年5月左右研發病毒入侵中國進行比特幣敲詐?
※程序員從接近底層的語言(如 C)學起,比起「不繞彎子」,直接從高級語言(如 PHP)開始,這兩種觀念之間的優劣對比是怎樣的?