首先描述一下我的坑是啥?我的坑就是写了一个对集料颗粒进行角度计算的类,在main函数中使用采用了类定义申明,这样使用导致一个坑,这个类中对于集料的数目进行了宏定义,发现数据如果超过20个,编译就报错,当时没有太在意这个坑,没有思考什么原因。也就将就者用了。
后来对接同事说,这个颗粒数目不能限制在20个,至少要100个。说我的类里面太多静态数组,这个消耗太多的内存空间了。需要换一种方法,改成动态方式,有多少就申请多少。我估计者这个类里面成员变量修改动作太大,还不如直接将类定义申明,修改成new方式动态申明,然后delete方式动态删除。
这里说一下查找内存情况,然后还让我查看电脑的内存有多大,win + r 然后输入dxdiag,这个是在Win 10中检查DirectX诊断工具版本,后续会附上DirectX的使用。除了通过DirectX诊断工具查看内存,也可以通过任务管理器了解内存,在任务栏右击,选择任务管理器,选中性能标签,就可以看到内存使用情况,总共有多少内存。还有可以通过右击电脑选择属性,选择“关于”,查看“设备规格”中的“自带RAM”。查出来内存有8G.
回到正题,内存有8G,但是我这边程序没有这么大,为啥受限呢。 所以想知道原因,主要类的局部变量,如果类定义申明,就是在栈空间,而这个栈空间是由操作系统控制的,根本没有用到所有的内存RAM的空间,下面说明了对于栈的空间,在Window下,栈的大小是2MB,Linux下,默认栈空间大小为8MB。而对于堆,比如32位系统最大不超过2G,而64位系统最大不超过4G,但相比较栈,这个堆的空间大多了。所以当需要分配一个非常大的内存时,请用new。所以这里将类动态申请,就将这个类需要很大空间放到堆那边了。
通过上面的梳理,可以知道内存的8个G是物理层面的概念,这个8个G可以进一步划分为操作系统和应用程序层面,就是栈和堆的概念。具体new使用方式和类定义申明方式的优缺点,可以参见下文。如果栈空间不够,编译不通过,或者运行溢出,指针乱飞。
说一个话外题,定义类用new方式定义,赋值给类的指针,配置100个颗粒了,编译通过了,但是运行指针飞了,比如访问数组超越边界,导致流程走到输出了selectnum的数据,我犯了一个小错误,认为selectnum之前都是正确的,其实这个前后都有问题,因为指针跑飞到这个selectnum, 是这个selectnum前面的代码导致的。所以想写这个贴子告知相关的编码的人员和我自己,不要犯这种定位问题的思路。所以我后来走读代码,发现测试代码半径数组设置为10,实际轮廓应该大于颗粒数据,因为有误判的轮廓,从而导致这个这个数组越界,导致指针跑飞,整个系统crash了。
一、new创建类对象与不new区别
new创建类对象需要指针接收
new创建类对象使用完需delete销毁
new创建对象直接使用堆空间,而局部不用new定义类对象则使用栈空间
new对象指针用途广泛,比如作为函数返回值、函数参数等
频繁调用场合并不适合new,就像new申请和释放内存一样
二、创建对象实例
1. 使用new创建对象
CTest* pTest = new CTest();
delete pTest;
pTest是用来接收类的对象指针。new申请的对象,则只有调用到delete时再会执行析构函数,如果程序退出而没有执行delete则会造成内存泄漏。
2. 不使用new,直接使用类定义声明:
CTest mTest;
一般作为局部变量或全局变量创建使用,此种创建方式,使用完后不需要手动释放,该类析构函数会自动执行,例如在一个函数内部作为局部变量创建使用,函数结束后系统会自动释放对应的栈空间不用手动delete。
#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,在堆中分配了内存,栈中内存的分配和释放是由系统管理,堆中内存的分配和释放必须由程序员手动释放。
三、总结
一般来说对于一个进程栈的大小远远小于堆的大小,在Window下,栈的大小是2MB,Linux下,默认栈空间大小为8MB。对于堆,比如32位系统最大不超过2G,而64位系统最大不超过4G,当需要分配一个非常大的内存时,请用new。
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。
堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在 堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就需要申请足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。
由上可知,一般情况不使用new,直接使用类定义声明,申请内存特别大的情况下,或者作为函数返回值时,使用new创建对象。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/u011555996/article/details/137423724