---
title : 01_Windwos_記憶體管理
---
# Windows_記憶體管理
By Cheng-Yen, Tsai
Date : 2021-05-21
---
## 壹、前言
在初步了解記憶體的運作原理後,我開始著手進行記憶體管理,開始操作簡單的記憶體配置、記憶體內容複製等等,目標是達到在windows靈活的操控記憶體。
---
## 貳、記憶體配置
### 01. 所需知識
* 堆積(Heap) : 因為每筆資料所需的空間都不一定相同,所以不可以對所有資料都配置相同大小的記憶體,所以便產生了heap這個記憶體空間。**此空間在得到配置請求時,會回傳一個指標。**
* 在windows中要進行動態記憶體配置,可以使用HeapAlloc()。如同C語言的malloc(),只是參數上的差別,在windows上,也可以使用malloc()加上free()來達到相同的效果,但是使用windows本身的API能夠做到更細部的控制。
* 使用HeapAlloc()有幾個條件,首先要先取的對heap的handle,簡單的做法是使用GetProcessHeap(),若成功,則回傳這個heap,失敗則回傳NULL。
* 然而,HeapAlloc()含有另外兩個參數,一個是旗標,在這裡我都設定成0(一般都是這樣),雖然還有兩三種選擇,但屬於更深入的部分了。另一個參數就是要配置的記憶體數量。
* 同樣的,若成功配置記憶體,則回傳配置好的記憶體位址,否則回傳NULL。
* 配置完記憶體後,接著要釋放記憶體,使用HeapFree()來操作,同樣的先取得heap的hendle,使用GetProcessHeap(),參數也有旗標(設定成0),最後是要釋放的記憶體。
* 下面是一個複製字串的程式:
```clike=
#include <windows.h>
#include <stdio.h>
int main() {
char aString[] = "Hello, world!";
int slen = strlen(aString);
char* pString = NULL;
printf("aString: [%s]\n", aString);
pString = (char *)HeapAlloc(GetProcessHeap(), 0, slen + 1);
if (NULL == pString){
printf("HeapAlloc() error\n");
return 1;
}
strcpy_s(pString, slen + 1, aString);
printf("pString: [%s]\n", pString);
HeapFree(GetProcessHeap(), 0, pString);
}
```
### 02. 困難點
* 在剛開始學習的過程,我無法理解為何需要宣告一個pString指標,直到我回頭查看資料才發現,在heap收到配置請求時,所回傳的是一個指標,所以當然需要宣告這個指標來操作。
* 在第14行的strcpy_s(),我也摸索了很久,之後在mincrosoft的文件中看到,是為了確保程式的安全性,後面接的s是safe的意思,在許多記憶體相關的函式都有此設定,在第一哥參數後面加上了長度的參數,代表目標記憶體大小,這樣可以避免記憶體過度的使用造成程式的錯誤和漏洞。
* HeapFree()的最後一個參數是指標,其原因也是一樣,對記憶體的操作要透過回傳的指標。
---
## 參、常用的記憶體函式
### 01. CopyMemory()
* Windows內使用CopyMemory()來搬動記憶體內容,相當於C語言裡的memcpy()。
* 其中有三個參數,第一個是目標位址,第二個是來源位址,最後是複製的記憶體數量,單位是byte。
* 下面是複製記憶體內容(字串)的程式:
```clike=
#include <windows.h>
#include <stdio.h>
int main() {
char aString1[] = "Hello, world!";
char aString2[100];
printf("aString1: [%s]\n", aString1);
CopyMemory(aString2, aString1, strlen(aString1) + 1);
printf("aString2: [%s]\n", aString2);
return 0;
}
```

* 剛開始我漏掉了最後的記憶體數量要加1的部分,原因是字串最後會有一個空字元。
* 另外來源跟目標是可以重疊的:
```clike=
#include <windows.h>
#include <stdio.h>
int main() {
char aString1[1024] = "Hello, world!";
printf("%s\n", aString1);
CopyMemory(aString1+7, aString1, strlen(aString1));
printf("%s\n", aString1);
return 0;
}
```

### 02. FillMemory() 與 ZeroMemory()
* 這兩個函式式用來設定記憶體內容的,前者是用來將一快記憶體內填滿指定的字元,等於C語言中的memset()。後者是將記憶體內填滿0,但其實我認為有點多此一舉,同樣的FillMemory()也可以做到。
* FillMemory()有三個參數,第一個是目標為址,第二個是填充的數量,最後是要用哪個字元填充。
* ZeroMemory()就只有前兩個參數設定。
* 下面是兩個函式的使用:
```clike=
#include <windows.h>
#include <stdio.h>
int main() {
char aString[] = "Hello, world!";
printf("aString: [%s]\n", aString);
FillMemory(aString, strlen(aString), '@');
printf("aString: [%s]\n", aString);
}
```

* 使用Fillmemory()替代Zeromemory()
```clike=
#include <windows.h>
#include <stdio.h>
int main() {
char aString[] = "Hello, world!";
printf("aString: [%s]\n", aString);
FillMemory(aString, strlen(aString), '\0');
printf("aString: [%s]\n", aString);
}
```
