欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

理解并掌握C++中的内存操控与内存工作原理

最编程 2024-02-24 13:37:07
...

内存分区模型

根据c++执行将内存大致划分为4个区域:

  1. 代码区,存放函数体的二进制,即CPU执行的机器指令,并且是只读的;代码区中存放的就是CPU执行的机器指令,代码区是共享和只读的,共享是指对于频繁被执行的程序,只需要在内存中有一份代码就行。而只读则表示防止程序意外修改指令
  2. 全局区(静态区),存放全局变量和静态变量。全局区是全局变量、静态变量和常量区、字符串常量和const修饰的常量存放在这里。代码区全局区在代码编译后就存在了
  3. 栈区,由编译器自动分配释放,存放函数形参,局部变量,返回值等。不要返回局部变量的地址,栈区的数据由编译器开辟和释放。形参数据也是放在栈区的。栈区和堆区是程序运行后才有
  4. 堆区,由程序员分配和释放,若程序员不释放,程序结束时由操作系统CPU释放,堆区由程序员开辟,若程序员不释放,则由操作系统回收

内存溢出与内存泄漏

内存溢出:指程序在申请内存时,没有足够的内存空间供其使用

内存泄露 :指程序在申请内存后,无法释放已申请的内存空间

new & delete

  • new创建类对象需要指针接收,new创建类对象使用完需delete销毁
  • new创建对象直接使用堆空间(或全局区的静态存储区)而局部不用new定义类对象则使用栈空间
  • new对象指针用途广泛,如作为函数返回值、函数参数等
  • 频繁调用场合并不适合new,就像new申请和释放内存一样

new操作符是从*存储区上为对象动态分配内存空间的,malloc函数是从堆上动态分配内存。*存储区是C++基于new操作符的一个抽象概念, 凡是通过new操作符进行内存申请的, 该内存称为*存储区。 而*存储区的位置取决于operator new的实现细节。*存储区不仅可以是堆, 也可以是静态存储区, 取决operator new在哪里为对象分配内存

使用new创建对象

CTest* pTest = new CTest();
delete pTest;

pTest是用来接收类的对象指针。new申请的对象,只有调用到delete时才会执行析构函数,如果程序退出而没有执行delete则会造成内存泄漏

不使用new,直接使用类定义声明

CTest mTest;

此种创建方式,使用完后不需要手动释放,该类析构函数会自动执行

#include <iostream>
using namespace std;
 
class A
{
private:
    int n;
public:
    A(int m):n(m)
    {
    }
    ~A(){}
};
 
int main()
{
    A a(1);  //栈中分配
    A b = A(1);  //栈中分配
    A* c = new A(1);  //堆中分配
delete c;
    return 0;
}

第一个隐式调用,第二个显式调用,两者都是在进程虚拟地址空间中的栈中分配内存,而第三种使用了new,在堆中分配了内存,栈中内存的分配和释放是由系统管理,堆中内存的分配和释放必须由程序员手动释放

栈是机器系统提供的,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高

堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就需要申请足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

一般情况不使用new,直接使用类定义声明,申请内存特别大的情况下,或者作为函数返回值时,使用new创建对象。

new的作用是:

  • 调用operator new分配空间。
  • 调用构造函数初始化对象。

new[ ]的作用

  • 调用operator new分配空间。
  • 调用N次构造函数分别初始化每个对象。

具体调用是,new分配内存时,先调用malloc后调用构造函数,释放空间时,先调用析构函数,后调用free。

malloc & free

malloc/free是C/C++标准库的函数,malloc/free只是动态分配内存空间/释放空间。而new/delete除了分配空间还会调用构造函数和析构函数进行初始化与清理(清理成员),通常情况下,C程序只能用malloc/free管理动态内存,malloc返回的是void*指针,单位是byte, 需要通过强转才能转成我们所需要的类型

(void *)malloc(int size) 
char *p = (char *)malloc(100);

malloc函数申请的是连续的一块内存,内存分配会失败,函数返回NULL,分配空间之后需要用if(NULL!=p)进行验证,free函数只有一个参数,就是所要释放的内存块的首地址

free(p);

malloc需要与free配套使用,同时注意只能free一次,释放完块内存之后,没有把指针置NULL,这个指针就成为了“野指针”,因此free完之后,一定要给指针置NULL。

栈与堆

栈是系统管理的内存空间,存储局部变量,临时对象,函数参数等,大小有限

堆是程序员管理的内存空间,常用于创建对象,空间大,存储常用对象,适用于多次调用,跨线程场景,应该永远记住堆的内存管理是否合理,否则出现内存泄漏

推荐阅读