作業系統
術語: 資料區,堆,棧,靜態區,常量區,全域性區,字串常量區,文字常量區,程式碼區等等
資料區包括 :堆,棧,全域性/靜態儲存區。
全域性/靜態儲存區包括:常量區,全域性區、靜態區。
常量區包括 :字串常量區、常變數區。
程式碼區 :存放程式編譯後的二進位制程式碼,不可定址區
程式到程序
1.可執行程式 需要有固定的格式
windows中可執行檔案是PE格式的,以exe作為字尾結尾
linux可執行檔案是ELF格式的,
Mach-O:常用於macOS系統
2.load-載入器透過可執行檔案頭部資訊,找到程式的入口點
檔案解析 --記憶體分配---檔案對映--符號解析
記憶體佈局 處理器從記憶體取指令和運算元,- 載入段到記憶體
外部儲存裝置是記憶體的後備儲存裝置。外部儲存裝置的內容只有被載入到內部儲存裝置中後才能被訪問
先載入到記憶體的快取記憶體區 ,從快取記憶體區讀取檔案頭,裡面存了程式碼段、資料段的起始和size資訊
載入器透過可執行檔案頭部資訊,找到程式的入口點 載入共享庫 設定程序環境 跳轉到入口
執行時庫初始化(如C執行時庫)。
初始化全域性物件(尤其是在C++中)
應用程式載入器Loader
3.跳轉程式的入口點,然後OS將CPU控制權交給新建立的程序
執行 fork/exec
fork()系統呼叫會透過複製一個現有程序來建立一個全新的程序
fork()函式:這是Unix/Linux系統中的一個系統呼叫,可以建立一個新的程序。
在呼叫fork()函式後,父程序會建立一個子程序,兩個程序將在fork()呼叫的位置繼續執行。
exec()函式族:在子程序中,可以使用exec()函式族中的一個函式來載入一個新的可執行檔案,並在當前程序空間中執行它。
exec()函式會取代當前程序的程式碼和數
wait():
用在父程序中等待子程序結束後,回收子程序,解除阻塞;若子程序一直沒有退出,則阻塞住父程序
exit和_exit:中止當前程序。exit()會先清理環境並呼叫終止處理程式,而_exit()不會進行任何清理直接終止程序
檔案
程式原始碼被編譯之後主要分成兩種段:
程式指令(程式碼區)和程式資料(資料區)。
程式碼段屬於程式指令,而資料域段和.bss段屬於程式資料
ELF(Executable Linkable Format)
物件檔案(Object files)有三個種類: 可重定位檔案( Relocatable File) 可執行檔案 可共享檔案
ELF檔案格式提供了兩種檢視,分別是連結檢視和執行檢視
連結檢視是以節(section)為單位,執行檢視是以段(segment)為單位
構成:ELF檔案由4部分組成,
分別是ELF頭(ELF header)、程式頭表(Program header table)、節/段(Section/Segments)和節頭表(Section header table )
segments是從執行的角度來描述elf檔案,sections是從連結的角度來描述elf檔案,一個segment包含若干個section
兩種不同的ELF格式映像
一種是靜態連結的,在裝入/啟動其執行時無需裝入函式庫映像、也無需進行動態連線。
另一種是動態連線,需要在裝入/啟動其執行時同時裝入函式庫映像並進行動態連結。
ELF 檔案載入
ELF檔案的動態載入機制主要依賴於動態連結器(dynamic linker),也稱為動態載入器(dynamic loader)。
Linux系統中通常是`/lib/ld-linux.so.2`
動態連結器負責在程式執行時解析ELF檔案中的動態連結資訊,載入所需的共享庫,並完成符號解析和重定位過程
記憶體模型
C語言中記憶體分佈及程式執行中(BSS段、資料段、程式碼段、堆疊)
#####
程式沒有載入到記憶體前,可執行程式內部已經分好3段資訊,分別為程式碼區(text)、資料區(data)和未初始化資料區(bss)3 個部分
執行可執行程式,作業系統把物理硬碟程式load(載入)到記憶體,
除了根據可執行程式的資訊分出程式碼區(text)、資料區(data)和未初始化資料區(bss)之外,
還額外增加了棧區、堆區
分割槽模型
重排序
編譯最佳化重排序 指令並行重排序 CPU 快取
編譯器有關(編譯最佳化重排序)、與處理器有關(指令並行重排序、CPU 快取)、與併發有關(CPU 快取)
記憶體屏障
依賴於作業系統std中的大部分內容(io, thread, file system, etc.)都需要作業系統的支援
不依賴於作業系統的rust的語言特性我們還是可以繼續使用
記憶體模型
作業系統記憶體模型--核心的記憶體模型
記憶體的訪問一致性(consistency/coherence)模型
核心中提供的各種記憶體屏障
從反編譯視角學習記憶體模型
Cangjie記憶體模型
3.倉頡語言支援自動記憶體管理,通常透過垃圾回收機制來管理記憶體的分配和釋放
Rust
Rust程式語言以其獨特的記憶體管理機制而著稱,
這一機制基於所有權(Ownership)、借用(Borrowing)和生命週期(Lifetimes)的概念
Go語言
記憶體模型的目的是為了定義清楚變數的讀寫在不同執行體裡的可見性。理解記憶體模型在併發程式設計中非常重要
Go的併發模型是基於CSP(Communicating Sequential Process)的,不同的Goroutine透過一種叫Channel的資料結構來通訊;
Java的併發模型則基於多執行緒和共享記憶體,有較多的概念(violatie, lock, final, construct, thread, atomic等)和場景
Java記憶體模型
1.
2.Java中,程式的載入、連結和初始化過程由JVM(Java虛擬機器)負責。
這個過程主要是透過類載入器(Class Loader)和其相關子系統來完成的
3.JVM記憶體模型其實就是
JVM在啟動的時候從作業系統記憶體中要了一塊大記憶體,然後將這個大記憶體分成
五個區域:方法區、堆區、虛擬機器棧、本地方法棧、本地方法棧、程式計數器.
其實叫JVM執行時區域更合適。但是要區分JVM記憶體模型與JMM(Java Memory Model)
讓使用者能控制的都是安全穩定的,有風險的操作都在門面之後,保證了作業系統的相對安全
Python記憶體模型
Python 在Python中,物件是核心概念之一。理解物件的基本組成和記憶體模型
型別(Type) 值(Value):物件的實際資料 引用計數(Reference Count)
Python使用引用計數來實現記憶體管理,當一個物件的引用計數為0時,記憶體將被回收。