C++之内存管理建议收藏

内存分配方式在C++中,内存分为内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。(1)堆就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

C++之内存管理建议收藏此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“”,获取验证码。在微信里搜索“”或者“”或者微信扫描右侧二维码都可以关注本站微信公众号。

  内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不在,内存泄漏几乎在每个C++程序中都会发生,因此要想成为C++高手,内存管理一关是必须要过的,除非放弃C++,转到Java或者.NET,他们的内存管理基本是自动的,当然你也放弃了自由和对内存的支配权,还放弃了C++超绝的性能。

内存分配方式

  在C++中,内存分为内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。

(1)堆

  就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。

(2)栈

  在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

(3)自由存储区

  就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。

(4)全局/静态存储区

  全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。

(5)常量存储区

  这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。

1. 堆和栈的区别

(1)管理方式

  对于栈来讲,是由编译器自动管理,无需我们手工控制;

  对于堆来说,释放工作由程序员控制,容易产生memory leak;

(2)空间大小

  一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的;

  但是对于栈来讲,一般都是有一定的空间大小的,我们可以修改;

(3)生长方向

  对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;

  对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长;

(4)分配方式

  堆都是动态分配的,没有静态分配的堆;

  栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。

  动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。

(5)分配效率

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

  堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低

(6)能否产生碎片

  对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低;

  对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列;

控制C++内存分配

  在嵌入式系统中使用C++的一个常见问题是内存分配,即对new 和 delete 操作符的失控。

  具有讽刺意味的是,问题的根源却是C++对内存的管理非常的容易而且安全。具体地说,当一个对象被消除时,它的析构函数能够安全的释放所分配的内存。

  这当然是个好事情,但是这种使用的简单性使得程序员们过度使用new 和 delete,而不注意在嵌入式C++环境中的因果关系。并且,在嵌入式系统中,由于内存的限制,频繁的动态分配不定大小的内存会引起很大的问题以及堆破碎的风险。

  作为忠告,保守的使用内存分配是嵌入式环境中的第一原则。

  但当你必须要使用new 和delete时,你不得不控制C++中的内存分配。你需要用一个全局的new 和delete来代替系统的内存分配符,并且一个类一个类的重载new 和delete。

  一个防止堆破碎的通用方法是从不同固定大小的内存持中分配不同类型的对象。对每个类重载new 和delete就提供了这样的控制。

1. 为单个类重载new和delete操作符

class TestClass {
public:
    TestClass()
    {
        cout << "TestClass()" << endl;
    }
    ~TestClass()
    {
        cout << "~TestClass()" << endl;
    }
    void * operator new(size_t size);
    void operator delete(void *p);
};

void *TestClass::operator new(size_t size)
{
    cout << "operator new" << endl;
    void *p = malloc(size);
    return (p);
}

void TestClass::operator delete(void *p)
{
    cout << "operator delete" << endl;
    free(p); 
}

void main()
{
    TestClass *pTest = new TestClass;
    delete pTest;
    pTest = NULL;
}

C++之内存管理建议收藏

2. 为单个类重载new[]和delete[]操作符

class TestClass {
public:
    TestClass()
    {
        cout << "TestClass()" << endl;
    }
    ~TestClass()
    {
        cout << "~TestClass()" << endl;
    }
    void * operator new[](size_t size);
    void operator delete[](void *p);
};

void *TestClass::operator new[](size_t size)
{
    cout << "operator new" << endl;
    void *p = malloc(size);
    return (p);
}

void TestClass::operator delete[](void *p)
{
    cout << "operator delete" << endl;
    free(p); 
}

void main()
{
    TestClass *pTest = new TestClass[5];
    delete[] pTest;
    pTest = NULL;
    return;
}

C++之内存管理建议收藏

特别特别要注意size_t nSize的大小!

C++new和delete实现原理:
https://blog.csdn.net/passion_wu128/article/details/38966581

常见的内存错误及其对策

1. 常见内存错误

  (1) 内存分配未成功,却使用了它

  (2)内存分配虽然成功,但是尚未初始化就引用它

  (3)内存分配成功并且已经初始化,但操作越过了内存的边界

  (4)忘记了释放内存,造成内存泄露

  (5) 释放了内存却继续使用它

2. 对策

  (1)用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存

  (2)不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用

  (3)避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作

  (4)动态内存的申请与释放必须配对,防止内存泄漏

  (5)用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/120161.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • shl归纳推理测试题库_逻辑推理测试题及答案-shl逻辑推理测试题目及答案[通俗易懂]

    shl归纳推理测试题库_逻辑推理测试题及答案-shl逻辑推理测试题目及答案[通俗易懂]公务员考试行政能力逻辑推理测试题及答案一1.所有市场经济搞得好的国家都是因为法律秩序比较好。其实建立市场并不难,一旦放开,人们受利益的驱使,市场很快就能形成,但是,一个没有秩序的市场一旦形成,再来整治就非常困难了。所以()。A.市场调节是“无形的手”,市场自发地处于稳定、均衡的状态B.要建立市场经济体制,必须高度重视法制建设C.市场经济的优越之处就在于它能使人们受利益驱使,因而能调动人的积极性D…

  • 黑盒测试用例设计方法总结

    黑盒测试用例设计方法总结把工作中用到的和在网上学到的测试用例方法总结一下。黑盒测试用例设计方法有包括等价类划分法、边界值分析法、错误推测法、因果图法、判定表驱动法、正交试验设计法等。 1.等价类常用于输入框,如账号密码输入框,内容分为有效等价类和无效等价类。写到表格中,然后按照表格写用例。可以分别写出账号和密码的用例2.边界值常用户输入框长度限制,如账号只允许输入12个字符,那么11个、1

  • java中的io流知识总结_java中的io流开发用的多吗

    java中的io流知识总结_java中的io流开发用的多吗通过前面的简单学习,我们已经能够大致了解了关于文件的操作,但是能够明显感受到在执行其他的操作的时候,还是会有一些不方便的地方存在,因此今天我们会学习另外四个IO流来帮助我们对文件进行操作,这四个流分别是缓冲流、转换流、序列化、打印流。好了,废话不多说,我直接开始今天的学习吧!……

    2022年10月20日
  • 清空标签间的内容(innerHTML)和 value

    清空标签间的内容(innerHTML)和 value

    2021年10月31日
  • GoLand 2021.7.20 激活码【永久激活】

    (GoLand 2021.7.20 激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html…

  • 联想笔记本电脑键盘灯在哪里开_笔记本电脑键盘字母键变成数字键

    联想笔记本电脑键盘灯在哪里开_笔记本电脑键盘字母键变成数字键在联想系列的笔记本电脑中,自带有键盘等的功能,不仅可以显得炫酷,还可以在光线比较暗的情况下打开键盘灯可以方便我们看清键盘上的按键,不过很多用户并不知道联想的键盘灯怎么开吧,其实有快捷键可以快速开启的,下面就给大家分享一下联想笔记本键盘亮灯按哪个键吧。具体步骤如下:1、联想笔记本部分型号具bai备键盘背光功能,方法通du过“FN+空格”打开,支持此功能的zhi机型,dao键盘上有相应标示。部分早期的…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号