記憶體相關知識(stack, heap, new, delete)
-
,是系統自行管理的stack
,用來專門存放區域變數,並會區域變數的生命徵期結束時自行釋放該區域變數。靜態記憶體空間
-
,是我們所自行管理的Heap
,我們使用new動態配置的空間都存放在這邊,需要我們自行手動delete釋放用不到的記憶體空間。動態記憶體空間
- 若再使
動態配置記憶體時,是存在記憶體的new
,並且在變數使用完之後記得要heap
delete
,釋放出記憶體,若沒有刪除動態配置的記憶體,則會造成該記憶體空間能然被占用,且造成記憶體空間破碎,而無法使往後在動態配置時,可以完整的配置剩餘空間,例如:
假設記憶體為4MB,而我們new了一個動態記憶體變數,系統自動在記憶體中間(系統自己判斷位置)使用了一塊100kb的記憶體,使用完後我們並沒有delete釋放,導致之後於法配置出完整的3.9MB(4MB-100KB),只剩下各半的大小,因為未試放的使用完的記體,導致記憶體破碎成兩半或者更多,所以不能完整的使用剩下的記憶體空間)
- 在函數內想要宣告區域變數在使用{ } 設定變數的生命週期,例如:
void fun1() {
int a;
{ int b; } //變數 b離開此大括號後系統及自動將其從stack釋放
}
- 使用迴圈注意迴圈內的迴圈變數(i = 1 ; i < 10 ; i ++)的i,清楚迴圈內是否處理到相關變數而導致當前的迴圈變數不同,例如:
for (i = 0 ; i < 10 ; i++){
...
if (i == 5)
i = 9; //在迴圈內另外操作迴圈變數,影響迴圈的運行次數,要注意流程!
...
}
- 在函數內使用外部與函數內同名的全域變數,需在變數前加上
即可使用,例如:::
int var = 100;
fun(){
int var = 1000;
cout << var << endl; //印出函數內的區域變數 var 1000
cout << ::var << endl; //印出全域變數 var 100
}
指標的使用
- 宣告指標時習慣初始化為
,避免指向未知的記憶體空間而導致不可預期錯誤null
-
宣告類別注意宣告成員變數的順序,會影響記憶體的對齊而影響類別大小(pacth對齊方式視編譯器設定)
例如:假設編輯器為預設(可到專案屬性中> C/C++ > Code Genertaion > Struct Member Alignment 調整)
註:類別的對齊大小(patch)一般情況下是視類別中最大的成員為基準,但若遇到系統多配置的空間,後面的元素可補上時,則會看是否對齊2 byte
class myClassA{
// 宣告變數的記憶體位置對齊 (未設計過的變數宣告)
int a; //4 byte
char b; //1 byte(系統再補3 byte對齊)
int c; //4 byte
char d; //1 byte(系統再補3 byte對齊)
};
class myClassB{
// 宣告變數的記憶體位置對齊 (設計過的變數宣告)
int a; //4 byte
int b; //4 byte
char c; //1 byte (系統再補 3 byte對齊)
char d; //1 byte (由於上述配有多餘空間,所以占用再上列所配置的空間,基於對齊方式是2的冪次方,上列c起碼會佔有2 byte,依順序來說是被安排在第11 byte的位置)
};
class myClassC{
// 對齊標準PATCH 先以類別中最大的資料型態為標準,再以 2 的冪次方作為第二的對齊參考 (示範以此類別以最大資料型態為對齊標準)
float c; // 4 byte (系統自動補 4 byte)
double a; // 8 byte (類別中最大的類型,以此作為 PATCH 對齊標準)
int b; // 4 byte (系統自動補4 byte)
};
class myClassD{
// 對齊標準PATCH 先以類別中最大的資料型態為標準,再以 2 的冪次方作為第二個的對齊參考 (示範2的冪次方為對齊方式)
double a; // 類別中最大資料型態 8 byte,作為對齊第一個標準
char b; // 1 byte (系統自動補 7 byte,加上以 2 的冪次方作為對齊的第二標準,所以至少占 2 byte,位在類別大小中的第 9、10 byte)
int c; // 4 byte (使用上列系統自動補的位置中,位在第 11~14 byte)
short d; // 2 byte (使用上列系統自動補的位置中,位在第 15、16 byte)
char e; // 1 byte (系統在自動補 7 byte)
};
int main(){
myClassA A; //A 記憶體大小為 16 byte
myClassB B; //B 記憶體大小為 12 byte
myClassC C; //C 記憶體大小為 24 byte
myClassD D; //D 記憶體大小為 24 byte
}
- 如果要將資料型態較大的變數存進STL容器中,建議使用
的方式做存取,例如存入類別到容器中,若使用指標,該容器只有所有指標的總和大小,若是放實體進去則是講整個類別的大小放進去,除了佔用大量記憶體,往後在做指標的運算也會佔用更多效能,例子如下:指標
備註:容器的實際大小為 [容器大小] + [容器內的資料數量] * [容器內的資料大小]
class myClass{
int a,b,c,d;
};
int main(){
myClass* myClassA = new myClass [5]; //動態宣告 5個 可存放myClass大小的記憶體空間,並由一個指標指向第一個物件
vector<myClass>myClassVecA;
for (int i = 0 ; i < 5 ; i++) {
myClassVecA.push_back(myClassA [i]);
} //執行完迴圈後myClassVecB的實際大小 = 12byte(vector容器的大小) + 5(元素個數) * 16byte(類別大小) = 92 byte
vector<myClass*>myClassVecB;
for (int i = 0 ; i < 5 ; i++) {
myClassVecB.push_back(&myClassA [i]);
} //執行完迴圈後myClassVecB的實際大小 = 12byte(vector容器的大小) + 5(元素個數) * 4byte(指標大小(依照系統而定)) = 32 byte
}