記錄學習內容。看網路上大大們的文章和影片,做些紀錄。
以下內容大多來自網路上大大們的文章。
還不了解,內容可能有錯誤。
https://www.youtube.com/watch?v=lx2tSY4joDg&ab_channel=.NETInterviewPreparationvideos
只需要Exe檔就可以執行了,其他兩個不需要。
【小黑馬作業系統教室統整】自編超齊全的「作業系統」科目學習整理
https://ithelp.ithome.com.tw/articles/10229671?sc=rss.qu
【小黑馬作業系統教室】(9) (Ch8) 記憶體管理,OS決定使用者寫程式的變數存在記憶體的哪個位置
https://ithelp.ithome.com.tw/articles/10229489
【小黑馬作業系統考古】範圍: 恐龍書第八章~第九章
https://ithelp.ithome.com.tw/articles/10229522
以下內容來自大大的文章:
當一個電腦使用者寫了一支程式,
要執行這支程式大致上有三個步驟:
1 由compiler編譯程式 (註:將人類可以看懂的程式碼轉為電腦看的懂的0101語言)
2 將程式讀進記憶體(memory)中
3 執行程式
一支程式裡會有許多變數,
變數放在記憶體的位置稱為變數的地址。
決定變數地址的行為稱為綁定(address binding),
那麼可以綁定變數地址的時機也就是上述說的三個時間點了:
- Compile time (compiler編譯程式時即決定地址)
- Load time (將程式讀進記憶體(memory)時才決定地址)
- Execution time (程式的時間動態決定地址)
開啟exe檔後,在用到dll套件的func時,exe檔會去 import .dll套件。
所以.dll套件的變數的地址 就是程式 Execution time 時決定的。
Compile time 時決定地址 想成:
真實地址直接寫死在程式裡, 之後製作exe檔 。
Load time (將程式讀進記憶體(memory)時才決定地址) 想成:
( 程式讀進記憶體後 ,開始為每個變數分配 真實地址 )
Execution time 想成:
Import .dll
// 以上是自己覺得好記的方法 ,內容應該錯誤。
https://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5%E5%BA%93
動態連結函式庫(Dynamic-link library,縮寫為DLL)
當執行檔呼叫到DLL檔內的函式(方法) 時,
Windows作業系統才會把DLL檔載入記憶體內,
DLL檔本身的結構就是可執行檔(exe),
當程式有需求時函式才進行連結。
透過動態連結方式,記憶體浪費的情形將可大幅降低。
維基寫得很詳盡 ,不過看不懂。
.Net 存取 INI Files
https://iammic.pixnet.net/blog/post/19789686-.net-%E5%AD%98%E5%8F%96-ini-files
會發現有這個東西
[DllImport("kernel32")]
改成這樣:
[DllImport("kernel321111")]
程式執行後,用到func時 ,才會發生錯誤:
System.DllNotFoundException: '無法載入 DLL 'kernel321111': 找不到指定的模組。 (發生例外狀況於 HRESULT: 0x8007007E)'
OS - Ch8 記憶體管理 Memory Management
https://mropengate.blogspot.com/2015/01/operating-system-ch8-memory-management.html
(像是dll 就是 重複使用的程式碼)
(這邊跟前面的 綁定變數地址的時機 ,有點混亂)
(總之 ,link或load代表 什麼時候 加入 另一隻程式(library)
,加入 另一隻程式 代不代表 另一隻程式的記憶體位址 也是這時候加入的 ? 我不知道,先理解到這 。)
Compile 時 library 就加入程式碼。
感覺好像 是指 在 變成一堆0101010 exe檔 前 , 套件和主程式 已經 合而為一了。
但好像不代表 : 套件的變數地址 ,在compile時決定 。
因為只是 套件和主程式 合而為一 ,還沒有要 決定他們的變數地址吧?
Dynamic linking是對於在很多支process之間,讓它們link相同的library,就不必每支process都存一個。
[DllImport("kernel32")] 就算這個嗎?
需要 OS 支持,不同 OS 有不同的稱呼。
Windows .dll (Dynamic Linking Libraries)
Linux .so (Shared Object)。
Dynamic loading是對一支process而言,在需要使用到函數時才讀進CPU中。
讓 programmer 在程式執行的過程中,動態決定要載入的libraries。
If (我需要dll)
載入dll 。
[DllImport("kernel32")] 算不算 Dynamic loading ?
感覺算 ,因為 用到 才會載入
觀察使用加入參考 的 dll 。
.NET Core 有一個檔案 是 專案名稱.csproj
裡面有這樣的內容 :
<ItemGroup>
<Reference Include="itextsharp">
<HintPath>..\..\..itextsharp.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>Dll\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
雖然 dll檔 在不同路徑 ,但是執行後
在 bin\Debug\netcoreapp3.1\
會新增同樣的dll檔案,跟exe檔放在同個目錄!!!
而且刪掉dll檔後,exe就開不起來了。
所以 這個方法 ,會在程式 編譯成exe時 ,把套件 複製一分到 同樣目錄下 。
exe檔 開不起來是因為 ,一開始 開exe 檔 ,程式就會自己 載入 套件 ? 發現目錄下沒有套件,就錯誤了?
Loading DLLs at runtime in C#
https://stackoverflow.com/questions/18362368/loading-dlls-at-runtime-in-c-sharp
var DLL = Assembly.LoadFile(@"C:\Users\test\Desktop\itextsharp.dll");
var class1Type = DLL.GetType("iTextSharp.text.pdf.parser.LocationTextExtractionStrategy");
dynamic c = Activator.CreateInstance(class1Type);
c.StartsWithSpace(@"Hello");
iTextSharp.text.pdf.parser.LocationTextExtractionStrategy 代表
c.StartsWithSpace(@"Hello");
表示 StartsWithSpace 方法 ,參數 是"Hello"
因為這個方法 是 private 所以會有這個錯誤:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: ''iTextSharp.text.pdf.parser.LocationTextExtractionStrategy.StartsWithSpace(string)' is inaccessible due to its protection level'
換一個方法:
c.StartsWithSpace(@"Hello"); 改成 c.BeginTextBlock();
總之程式可以正常執行了 。
目前猜測這樣寫 ,只會載一份而已
for (int i = 0; i <= 100; i++)
{
Assembly.LoadFile(@"C:\Users\test\Desktop\itextsharp.dll");
}
因為這個只出現一次:
TestDLLLoad.exe' (CLR v4.0.30319: TestDLLLoad.exe): 已載入 'C:\Users\test\Desktop\itextsharp.dll'。建置的模組沒有符號。
看這部教學:
計算機組織 Chapter 2.11 Linking object files - 朱宗賢老師
https://www.youtube.com/watch?v=uTIjdnMstBc&list=PLylnxZnYW9LbVL5HnYwo7VLmlkhM7lTey&index=18&ab_channel=edwardchu
講到 把多個檔案 (assembler) 經過 linker 後 變 exe檔 。
看不太懂 ,了解了一些:
load 和 save 指令 的機器語言 ,後面的16位的bit ,是 有號數(正數或負數)
多個檔案 (assembler) 在還沒合併前 ,位址都寫0 之類的 。
合併成exe 後 ,才會把 記憶體位址 補上 。
但是這個記憶體位址 , 是邏輯位址 ,還是 真實位址 ? 我不知道 。
關於一個程式 ,在記憶體中的配置 ?
OS - Ch3 行程 Process
https://mropengate.blogspot.com/2015/01/operating-system-ch3-processes.html
C 語言程式的記憶體配置概念教學
https://blog.gtwang.org/programming/memory-layout-of-c-program/
以下內容來自大大的文章:
stack : 存放函數的參數、區域變數等。
每一次的函數呼叫就會在堆疊區段建立一個 stack frame,儲存該次呼叫的所有變數與狀態,這樣一來同一個函數重複被呼叫時就會有不同的 stack frame,不會互相干擾,遞迴函數就是透過這樣的機制來執行的。
heap : 一般由程式設計師分配釋放,執行時才會知道配置大小,如 malloc/new 和 free/delete。
C 語言的 malloc 以及 C++ 的 new 所建立的變數都是儲存於此。
BSS :全域變數(global variables)以及靜態變數(static variables),但是沒有初始化(沒有給值) 。
這些變數在程式執行之前 會被系統初始化為 0 或是 null。
data : 全域變數(global variables)以及靜態變數(static variables),有給值,像是 static int a=123
text : 文字區段(text segment)也稱為程式碼區段(code segment),這裡存放的是可執行的 CPU 指令(instructions)、常數(像是123456)。
所以程式部分(sw lw jal 指令) 屬於text/code 。
初始化就是有給值,未初始化話就是沒給值
int a=0; //data 區塊 因為 global 和 給值
char *p1; // BSS 區塊 因為 global 和沒給值
double global[30]; // BSS 區塊 因為 global 和沒給值
main(){
int b; // stack 區塊 ,因為區域變數
int c = 1; // stack 區塊 ,因為區域變數
static int z; // bss區塊,因為 有static 和 沒給值
static int c=0; // data區塊 ,因為static和有給值
char *p3="123456"; // 123456\0 在text區塊, 因為123456算是常量。
//p3 在stack 區塊 ,因為區域變數 。
p2 = (char*)malloc(20); //heap 區塊 ,因為malloc
strcpy(p1,"123456");
//123456\0 在常量區,編譯器可能會將它與 p3 中的 123456\0 優化成一個地方。
}
還不了解,內容可能有錯誤。