如果知道我会死在哪里,那我将永远不去那个地方 -查理 芒格
前言
内存的操作和管理涉及东西较多且散,为便于查看,整理归纳成此文。可能有不全面之处,望大家批评指正。所有内容(见下图),我本想为了一次性更完,但是阅读体验不佳。遂将其拆分为两部分,此为其一。
内存布局
C++ 中的内存布局是由编译器和操作系统共同决定的。一般来说,C++ 中的内存布局可以分为以下几个部分:
栈内存使用
#include <iostream>
void stackMemoryExample() {
int localVar = 10; // 局部变量,存储在栈上
std::cout << "Stack Memory Example: " << localVar << std::endl;
} // localVar 在函数结束时被销毁
堆内存使用
#include <iostream>
void heapMemoryExample() {
int* dynamicVar = new int(20); // 动态分配内存,存储在堆上
std::cout << "Heap Memory Example: " << *dynamicVar << std::endl;
delete dynamicVar; // 释放堆上的内存,防止内存泄漏
}
内存分类
C++程序的内存管理涉及物理内存和虚拟内存。而物理内存和虚拟内存的桥梁为存管理单元(MMU)。
动态内存分配
C++中可以使用new/delete及malloc/free来操作动态内存。
new和malloc的区别和联系
new分配内存
int* myInt = new int; // 分配一个整数的内存
//一些操作
delete myInt;
new分配数组
int* p = new int[5];
for(int i =0; i<5;i++)
{
p[i]=i;
}
for(int i =0; i<5;i++)
{
std::cout<<p[i]<<"\n";
}
delete []p;
malloc分配内存
int* p = (int*)malloc(5*sizeof(int));
for(int i =0; i<5;i++)
{
p[i]=i;
}
for(int i =0; i<5;i++)
{
std::cout<<p[i]<<"\n";
}
free(p);
malloc分配多级内存
int** p = (int**)malloc(5*sizeof(int*));
for(int i =0; i<5;i++)
{
p[i]=(int*)malloc(2*sizeof(int));
p[i][0]=i*i+0;
p[i][1]=i*i+1;
}
for(int i =0; i<5;i++)
{
std::cout<<p[i][0]<<"\t"<<p[i][1]<<"\n";
}
for(int i =0; i<5;i++)
{
free(p[i]);
}
free(p);
操作动态内存可能存在的问题
内存泄漏
顾名思义,申请内存后没有释放,如new/delete、new[]/[]delete、malloc/free未能配套使用。通常意义上分为两种情况:(1)动态分配的内存没有释放;(2)虽然释放内存但是存在指向丢失导致的泄露
int main()
{
int* p = new int;
*p = 10;
//no delete,memory leak
return 0;
}
int main()
{
int* p = new int;//this pointer will memory leak
p = new int;
*p = 10;
free(p);
return 0;
}
解决方法:配套使用,或使用智能指针
野指针
指针定义后未初始化,致使指针指向的内存是无效值/随机值。
int* ptr = new int;
std::cout<<*ptr;//此时即为野指针
解决方法:定义即初始化,如果不确认指向,可指向nullptr
悬挂指针
一个曾经指向有效内存区域,但后来该内存区域被释放或重新分配,而指针仍保留原来的值,导致无法再通过该指针访问该内存区域
int* ptr = new int(10);
delete ptr;
//此后如果再次使用ptr,ptr即为悬挂指针
内存释放后立刻将指针指向nullptr
double free
指针释放后再次释放会触发访问冲突崩溃,如下实例代码
void test_memory_double_free()
{
int* p = new int;
delete p;
p=nullptr;//if commit this line will trigger break point
delete p;
}
解决方法:指针释放后立刻将其指向nullptr
内存碎片和效率
内存碎片和效率主要存在于大量申请和释放内存的场景。频繁的内存申请和释放可能会导致内存的空存在大量碎片,致使分配大空间内存时内存不够;同时,内存的申请和释放是有CPU耗时的,过多的申请和释放会存在效率问题的。
解决方法:内存池,见后期文章
好习惯推荐:指针使用前检查其是否为nullptr,定义和释放后立刻将其指向nullptr