---
# System prepended metadata

title: 01_Windwos_記憶體管理

---

---
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;
}
```
![](https://i.imgur.com/wjBeL20.png)

* 剛開始我漏掉了最後的記憶體數量要加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;
}
```
![](https://i.imgur.com/sDzeapx.png)


### 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);
}
```
![](https://i.imgur.com/wYgRuXP.png)
* 使用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);
}
```
![](https://i.imgur.com/3fd8jqu.png)
