IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++内存 -> 正文阅读

[C++知识库]C++内存

内存

一丶内存分配方式
C++中内存分为五个区,分别是栈(stack),堆(heap),自由存储区,全局/静态存储区(bss),常量存储区

:在执行函数时,函数内局部变量的存储单元,函数参数都可以在栈上创建,函数执行结束时这些存储单元自动被释放,栈内存分配运算内置于处理器指令集中,效率高,但分配内存容量有限。
:那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete,如果程序员没有释放掉,程序结束后,操作系统会自动回收(内存泄漏不是系统无法回收那片内存,而是你自己的应用程序无法使用那片内存。操作系统本身就有管理内存的职责,在进程结束后,操作系统会自动回收内存的)
自由存储区:就是那些由malloc等分配的内存块,他和堆是十分相似的,不过他是用free来结束自己的生命的
引申出来的问题:
很多编译器中new/delete都是以melloc和/free为基础实现的,那么就会引申出一个问题,自由存储区和堆相同么?
答案:堆是操作系统维护的一块内存,而自由存储时c++中通过new和delete动态分配和释放对象的抽象概念,堆和自由存储区并不等价
全局/静态存储区
全局变量和静态变量被分配到同一块内存中,在以前的c语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区
常量存储区
这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改

二丶堆和栈的区别

void func() {
    int* p = new int[5];
}

在这条语句里,看到了new就想到分配了一块堆内存,而指针p分配了一块栈内存。这句话的意思是,在栈内存中存放了一个指向对内存的指针p

堆和栈的区别主要分为以下六点:
1.管理方式不同:
对于栈来说,是编译器自动管理的,不需要我们手动控制
对于堆来说,释放工作由程序员控制,容易产生内存泄漏
2.空间大小:
一般在32位系统下,堆内存可以达到4g空间
对于栈来说,一般是有一定的空间大小,vc下面栈的空间默认1M(可以通过编译器设置修改)
3.碎片问题:
对于堆来说,频繁的new/delete势必会造成内存空间不连续,从而造成大量碎片,使程序效率降低
对于栈来说,不会存在这个问题,因为栈使先进后出的队列,他们一一对应,永远不可能邮一个内存块从栈中间弹出,在他弹出之前,它上面的后进的栈内容已被弹出
4.生长方向:
对于堆来说,生长方向是向上的,也就是向着内存地址增加的方向
对于栈来说,它的生长方向是向下的,是向着内存地址减小的方向增长
5.分配方式不同:
堆都是动态分配的
栈有两种分配方式动态分配和静态分配,静态分配是编译器完成的,比如局部变量的分配,动态分配是由alloca完成的,栈的动态分配是由编译器进行释放,无需我们手动实现
6.分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。
堆则是C/C++函数库提供的,他的机制很是复杂,例如为了分配一块内存,库函数会按照一定的算法在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间,就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分配到足够大小的内存,然后进行返回,显然,堆的效率比栈要低的多

虽然栈有众多好处,但是和堆比不是那么灵活,有时候分配大量的内存空间,还是堆好一些

三丶常见的内存错误及其对策
1.内存分配未成功,却使用了它
常见的解决办法是在使用内存之前检查指针是否为NULL。如果指针是函数的参数,那么在函数入口处用assert(p!=NULL)进行检查。如果是用malloc或new来申请内存,应该用if(p==NULL)或if(p!=NULL)进行防错处理

2.内存分配虽然成功,但是尚未初始化就引用它
犯这种错误主要是有两个起因:一是没有初始化的概念,二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。内存的缺省初值究竟是什么没有统一的标准,尽管有时候为零值,我们宁可信其无不可信其有。所以无论如何用哪种方式创建数组,都别忘了赋初值,即使是赋零值也不可省略,不要嫌麻烦。

3.内存分配成功已经初始化,但操作越过了内存的边界
例如在使用数组时经常发生下标”多1“或者”少1“的操作。特别是在for循环语句中,循环次数很容易搞错,导致数组越界

4.忘记了释放内存,造成内存泄露
含有这种错误的函数每被调用一次就会丢失一块内存,刚开始时系统的内存充足,你看不到错误。终有一次程序突然死掉,系统出现提示:内存耗尽。动态的申请和释放必须配对,程序中malloc与free的次数一定要相同,否则肯定有错误

5.释放了内存却继续使用它
有三种情况:
1)程序中的对象调用过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理混乱的局面
2)函数的return语句写错了,注意不要返回指向”栈内存“的指针”或者引用“,因为该内存在函数体结束时被自动销毁
3)使用free或delete释放了内存后,没有将指针设置为NULL,导致产生”野指针“

【规则1】在使用malloc或new申请内存之后,应该立即检查指针值是否为NULL,防止使用指针值作为NULL的内存
【规则2】不要忘记为数组或动态内存赋初值。防止将违背初始化的内存作为右值使用
【规则3】避免数组或指针下标越界,特别当心发生”多1“或者”少1“操作
【规则4】动态内存的申请和释放必须配对,防止内存泄露
【规则5】用free或delete释放内存之后,立即将指针设置为NULL,防止产生野指针

四丶野指针
”野指针“不是NULL指针,是指向”垃圾“内存的指针。人们一般不会用错NULL指针,因为用if语句很容易判断,但是野指针是很危险的,if语句对它不起作用,”野指针“的成因主要有两种
1.指针变量没有初始化,任何指针变量被创建时不会自动成为NULL,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存

char *p = NULL;
char *str = (char *)malloc(100);

2.指针p被free或者delete之后,没有置为NULL,让人误以为p是一个合法的指针
3.指针操作超越了变量的作用域范围,这种情况让人防不胜防

class A {
public:
    void Func(void) {
        cout << "Func of class A" << endl;
    }
};

void Test(void) {
    A *p;
    {
        A a;
        p = &a;//注意a的生命周期
    }
    p->Func();//p是"野指针"
}

函数Test在执行语句p->Func()时,对象a已经消失,而p是指向a的,所以p就成了野指针,但奇怪的是这个程序没有报错,可能和编译器有关

五丶内存耗尽怎么办
如果在申请动态内存时找不到足够大的内存块,malloc和new将返回NULL指针,宣告内存申请失败。通常有三种方式处理”内存耗尽“问题
1.判断指针是否为NULL,如果是则马上用return语句终止本函数,例如:

void Func(void) {
    A* a = new A;
    if (a == NULL) {
        return;
    }
}

2.判断指针是否为NULL,如果是则马上用exit(1)终止整个程序的运行,例如:

void Func(void) {
    A* a = new A;
    if (a == NULL) {
        exit(1);
    }
}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-27 13:54:18  更:2021-09-27 13:56:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:20:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码