内存分配访问无效:C++内存分配的 5种思路方法的区别

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

  栈就是那些由编译器在需要时候分配在不需要时候自动清楚变量存储区里面变量通常是局部变量、参数等

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

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

  全局/静态存储区全局变量和静态变量被分配到同块内存中在以前C语言中全局变量又分为和未在C里面没有这个区分了他们共同占用同块内存区

  常量存储区这是块比较特殊存储区他们里面存放是常量不允许修改(当然你要通过非正当手段也可以修改而且思路方法很多const研究文中我给出了6种思路方法)

  明确区分堆和栈

  在bbs上堆和栈区分问题似乎是个永恒话题由此可见初学者对此往往是混淆不清所以我决定拿他第个开刀

  首先我们举个例子:

void f { * p= [5]; }

  这条短短句话就包含了堆和栈看到我们首先就应该想到我们分配了块堆内存那么指针p呢?他分配块栈内存所以这句话意思就是:在栈内存中存放了个指向块堆内存指针p会先确定在堆中分配内存大小然后operator 分配内存然后返回这块内存首地址放入栈中他在VC6下汇编代码如下:

00401028 push 14h
0040102A call operator (00401060)
0040102F add esp,4
00401032 mov dword ptr [ebp-8],eax
00401035 mov eax,dword ptr [ebp-8]
00401038 mov dword ptr [ebp-4],eax

  这里我们为了简单并没有释放内存那么该如何去释放呢?是delete p么?澳错了应该是delete p这是为了告诉编译器:我删除VC6就会根据相应Cookie信息去进行释放内存工作

  好了我们回到我们主题:堆和栈究竟有什么区别?

  主要区别由以下几点:

  1、管理方式区别;

  2、空间大小区别;

  3、能否产生碎片区别;

  4、生长方向区别;

  5、分配方式区别;

  6、分配效率区别;

  管理方式:对于栈来讲是由编译器自动管理无需我们手工控制;对于堆来说释放工作由员控制容易产生memory leak

  空间大小:般来讲在32位系统下堆内存可以达到4G空间从这个角度来看堆内存几乎是没有什么限制但是对于栈来讲般都是有空间大小例如在VC6下面默认栈空间大小是1M(好像是记不清楚了)当然我们可以修改:

  打开工程依次操作菜单如下:Project->Setting->Link在Category 中选中Output然后在Reserve中设定堆栈最大值和commit

  注意:reserve最小值为4Byte;commit是保留在虚拟内存页文件里面它设置较大会使栈开辟较大可能增加内存开销和启动时间

  碎片问题:对于堆来讲频繁/delete势必会造成内存空间不连续从而造成大量碎片使效率降低对于栈来讲则不会存在这个问题栈是先进后出队列他们是如此对应以至于永远都不可能有个内存块从栈中间弹出在他弹出的前在他上面后进栈内容已经被弹出详细可以参考数据结构这里我们就不再讨论了

  生长方向:对于堆来讲生长方向是向上也就是向着内存地址增加方向;对于栈来讲生长方向是向下是向着内存地址减小方向增长

  分配方式:堆都是动态分配没有静态分配栈有2种分配方式:静态分配和动态分配静态分配是编译器完成比如局部变量分配动态分配由alloca进行分配但是栈动态分配和堆是区别动态分配是由编译器进行释放无需我们手工实现

  分配效率:栈是机器系统提供数据结构计算机会在底层对栈提供支持:分配专门寄存器存放栈地址压栈出栈都有专门指令执行这就决定了栈效率比较高堆则是C/C库提供机制是很复杂例如为了分配块内存会按照算法(具体算法可以参考数据结构/操作系统)在堆内存中搜索可用足够大小空间如果没有足够大小空间(可能是由于内存碎片太多)就有可能系统功能去增加数据段内存空间这样就有机会分到足够大小内存然后进行返回显然效率比栈要低得多

  从这里我们可以看到堆和栈相比由于大量/delete使用容易造成大量内存碎片;由于没有专门系统支持效率很低;由于可能引发用户态和核心态切换内存申请代价变得更加昂贵所以栈在中是应用最广泛就算是也利用栈去完成过程中参数返回地址EBP和局部变量都采用栈方式存放所以我们推荐大家尽量用栈而不是用堆

  虽然栈有如此众多好处但是由于和堆相比不是那么灵活有时候分配大量内存空间还是用堆好

  无论是堆还是栈都要防止越界现象发生(除非你是故意使其越界)越界结果要么是崩溃要么是摧毁堆、栈结构产生以想不到结果,就算是在你运行过程中没有发生上面问题你还是要小心说不定什么时候就崩掉那时候debug可是相当困难:)
Tags:  如何分配虚拟内存 内存和硬盘的区别 内存分配 内存分配访问无效

延伸阅读

最新评论

发表评论