1.C++的內存分佈
int value = 1;
static int staticvalue = 1;
void Test()
{
static int staval = 1;
int val = 1;
int num1 = {1,2,3,4};
char char2[] = "abcd";
char* char3 = "abcd";
int* ptr1 = (int*)malloc(sizeof (int)*4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int)*4);
free (ptr1);
free (ptr3);
}
選項: A.棧 B.堆 C.數據段 D.代碼段
value 在哪裏?C_____ staticvalue 在哪裏?C____
staval 在哪裏?C_____ val 在哪裏?A______
num1 在哪裏?A_____
char2在哪裏?D____ * char2在哪裏?A_____
char3在哪裏?D____ *pChar3在哪裏?A_____
ptr1在哪裏?B____ *ptr1在哪裏?A____
sizeof(num1) = 40___
sizeof(char2) = 5_
strlen(char2) = _4
sizeof(char3) = _4
strlen(char3) = ___4
sizeof(ptr1) = _4
注意:內存空間從上到下分爲6個部分:內核空間,棧,內存映射段,堆,數據段,代碼段
- 1.棧又叫堆棧,存儲非靜態局部變量 / 函數參數 / 返回值,棧是向下生長的。
- 2.內存映射段是高效的I/O映射方式,用於裝載一個共享的動態內存庫,用戶可以使用系統接口創建共享內存,做進程間通信。(存儲文件映射、動態庫、匿名映射)
- 3.堆用於程序運行時動態內存分配,堆是向上增長的。
- 4.數據段存儲全局數據和靜態數據
- 5.代碼段存儲可執行的代碼 / 只讀常量
2.C語言中的動態內存管理方式
void Test()
{
int *p1 = (int* ) malloc(sizeof(int));
free(p1);
int *p2 = (int* ) calloc(4,sizeof(int));
int *p3 = (int* ) realloc(p2,sizeof(int)*10);
free(p3);
}
3.C++內存管理方式
1.new/ / delete申請和釋放空間
void Test()
{
//動態申請一個int類型的空間
int* p4 = new int;
//動態申請一個int類型的空間並初始化爲10
int* p5 = new int(10);
//動態申請5個int類型的空間
int* p6 = new int[5];
delete p4'
delete p5;
delete [] p6;
}
2.operator new 和 opreator delete 函數
注意:new和delete是用戶進行動態內存申請和釋放的操作符,
operator new和operator delete是系統提供的全局函數。
new在底層調用operator new全局函數來申請空間,delete在底層調用operator delete全局函數來釋放空間
operator new:該函數實際通過malloc來釋放空間,當malloc申請空間成功則返回;申請空間失敗,則執行空間不足應對措施,如果改應對措施用戶設置了,則繼續申請,否則拋異常。
operator delete:最終是通過free來釋放空間的。
4.new和delete的實現原理
1.內置類型
- 如果申請的是內置類型的空間,new和malloc,delete和free基本類似,不同的地方:new/delete申請和釋放的是單個元素的空間,new[]和delete[]申請的是連續空間,而且new在申請空間失敗後會拋出異常。
2.自定義類型 - new的原理
1.調用operator new函數申請空間。
2.在申請空間上執行構造函數,完成對對象的構造。 - delete的原理
1.在空間中執行析構函數,完成對象中資源的清理工作。
2.調用operator delete函數釋放空間。 - new T[n]的原理
1.調用operator new[ ]函數,在operator new[ ]中調用operator new函數完成n個對象空間的申請。
2.在申請的空間上執行n次構造函數。 - delete [ ]的原理
1.在釋放的對象空間上執行n次析構函數,完成對n個對象中資源的清理
2.調用operator delete[ ]釋放空間,實際在operator delete[ ]調用operator delete來釋放空間。
class Test()
{
public:
Test()
:_data(data)
{
std::cout << "Test()" << std::endl;
}
~Test()
{
std::cout << "~Test()" << std::endl;
}
private:
int _date;
}
int main()
{
//申請一個數據得空間
Test* p1 = new Test;
delete p1;
//申請10格數據的空間
Test* p2 = new Test[10];
delete [] p2;
system("pause");
return 0;
}
面試題
1.malloc / calloc / realloc 之間的區別?
答:malloc與calloc的區別爲1塊與n塊的區別:
(1)malloc用於申請一段新的地址,參數size爲需要內存空間的長度
(2)calloc與malloc相似,參數size爲申請地址的單位元素長度,n爲元素個數
(3)realloc是給一個已經分配了地址的指針重新分配空間,參數ptr爲原有的空間地址,newsize是重新申請的地址長度
malloc調用形式爲(類型*)malloc(size):在內存的動態存儲區中分配一塊長度爲“size”字節的連續區域,返回該區域的首地址。
calloc調用形式爲(類型*)calloc(n,size):在內存的動態存儲區中分配n塊長度爲“size”字節的連續區域,返回首地址。
realloc調用形式爲(類型*)realloc(*ptr,size):將ptr內存大小增大到size。
2.malloc / free 和new / delete的區別?
答:共同點:都是從堆上申請空間,並且需要用戶手動釋放
不同點:
- 1.malloc和free是函數,new和delete是操作符。
- 2.malloc申請的空間不會初始化,new可以初始化。
- 3.malloc申請空間時,需要手動計算大小並傳遞,new只需要在其後跟上空間的類型即可。
- 4.malloc的返回值爲void*,在使用這個函數的時候必須強轉,new不需要,因爲new後面跟的是空間的類型
- 5.malloc在申請空間失敗時,返回值爲nullptr,因此使用的時候必須判空。new不需要,但是new必須捕獲異常。
- 6.申請自定義類型對象的時候,malloc / free只會開闢空間,不會調用構造函數和析構函數,而new在申請空間的時候會調用構造函數完成對象的初始化,delete在釋放空間的時候會調用析構函數完成空間中資源的清理。
- 7.new / delete比malloc / free的效率稍微低點,因爲new / delete的底層封裝了malloc / free
3.請設計一個類,該類只能在堆上創建對象
答:構造函數私有化
(1)將類的構造函數私有,拷貝構造聲明爲私有,防止別人調用拷貝構造在棧上生成空間。
(2)提供一個靜態成員函數,在該靜態成員函數中完成對象的創建。
class A
{
protected :
A(){}
~A(){}
public :
static A* create()
{
return new A();
}
void destory()
{
delete this ;
}
};
//這樣,調用create()函數在堆上創建類A對象,調用destory()函數釋放內存。
4.請設計一個類,該類只能在棧上創建對象
只有使用new運算符,對象纔會建立在堆上,因此,只要禁用new運算符就可以實現類對象只能建立在棧上。將operator new()設爲私有即可。
代碼如下:
class A
{
private :
void * operator new ( size_t t){} // 注意函數的第一個參數和返回值都是固定的
void operator delete ( void * ptr){} // 重載了new就需要重載delete
public :
A(){}
~A(){}
};
5.什麼是內存泄漏?
答:內存泄漏是因爲疏忽或者是錯誤造成程序未能釋放已經不能再使用的情況,內存泄漏並不是指內存在物理上的消失,而是應用程序分配某段內存的時候,因爲設計錯誤,失去了對該段內存的控制,因此造成內存浪費。
void MemoryLeaks()
{
// 1.內存申請了忘記釋放
int* p1 = (int*)malloc(sizeof(int));
int* p2 = new int;
// 2.異常安全問題
int* p3 = new int[10];
Func();// 這裏Func函數拋異常導致delete[] p3未執行,p3沒被釋放.
delete[] p3;
}
6.內存泄漏分類
- 1.堆內存分類
堆內存是指程序運行的時候要通過malloc / calloc / realloc / new等從堆中分配出一段內存,用完之後必須要調用相應的free和delete刪掉。假設程序的設計錯誤導致這部分內存沒有被釋放,那麼這部分空間將無法再被使用,就會產生Heap Leak. - 2.系統資源泄漏
指程序使用系統分配的資源,比如套接字,文件描述符,管道等的時候,沒有使用對應的函數將其釋放掉,導致系統資源的浪費,嚴重可導致系統效能減少,系統執行不穩定。
7.如何避免內存泄漏?
- 1.工程前期良好的設計規範,養成良好的編碼規範,申請的空間記得去釋放
ps:但是如果在釋放之前有異常的話,就算釋放了,也還會出現問題,那麼就需要智能指針來進行管理。 - 2.採用RALL思想或者只能指針管理資源。
- 3.些公司內部規範使用內部實現的私有內存管理庫。這套庫自帶內存泄漏檢測的功能選項。
內存泄漏非常常見,解決方案分爲兩種:1、事前預防型。如智能指針等。2、事後查錯型。如泄漏檢測工 具。
8.如何一次在堆上申請4G的空間?
// 將程序編譯成x64的進程,運行下面的程序試試?
#include <iostream>
using namespace std;
int main()
{
void* p = new char[0xfffffffful];
cout << "new:" << p << endl;
return 0;
}