yuyixuantai的笔记 https://bbs.21ic.com/?476561 [收藏] [复制] [RSS] 我思,我在,我行于固件程序之旅

日志

堆内存与栈内存小议(原创)

已有 3677 次阅读2008-3-28 00:33 |系统分类:嵌入式系统| 堆栈, 内存

    在标准C语言上,使用malloc等内存分配函数获取内存既是从堆中分配内存,而在一个函数体中例如定义一个数组之类的操作是从栈中分配内存。


    从堆中分配的内存需要程序员手动释放,如果不释放,而系统内存管理器又不自动回收这些堆内存的话(实现这一项功能的系统很少),那就一直被占用。而栈内存在函数体内一直存在,你无法丢掉,在离开函数体后,立即被销毁,你无法挽留。


    如果老是申请堆内存,而不释放,内存会越来越少,很明显的结果是系统变慢或者申请不到新的堆内存。而过度的申请栈内存(可以试试在函数中申请一个1G的数组!),会导致栈被压爆,结果是灾难性的。栈都爆了,谁知道函数会跑到哪里去?!


    我们掌握堆内存的权柄就是返回的指针,一旦丢掉了指针,便无法在我们视野内释放它。这便是内存泄露。而如果在函数中申请一个数组,在函数体外调用使用这块栈内存,结果谁也无法预测。
  
    申请栈内存的时间是基本确定的。核心只要栈指针的偏移和对它进行初始化(如果必要的话)。但堆中的时间是无法预测的,这是内存管理器的任务,跟他的算法和当前的堆内存结构有关,也许很快,也许很慢。两者在这里不存在可比性,尽管大多数情况下栈内存的申请的确比堆内存要快。
    申请的时候,栈内存几乎等同与申请大小,大多数的偏差是内存对齐引发的几个字节影响。但对内存但实际也会会相差很大(这主要源于内存管理器算法)。常见的内存管理都是按照基本内存块大小来分配的。在一个基本单元是1024Byte的管理器上,哪怕你只申请一个Byte,它也会给你1024个。频繁的申请小的堆内存是不明智的。
    在申请和销毁之外的使用过程中,他们是一样,可以同样对待。一般情况下,他们具有同样的访问速度,都不要进行越界访问,哪怕堆内存先后越界暂时不会出错。


    栈内存和堆内存的大小也没有可比性。栈内存大小跟IC,编译器,OS相关。而对堆内存的大小一般是内存管理器说了算。X86上Windos下VC编译的代码只是N种情况之一。并不具备多少代表性。至于磁盘是否能为堆内存撑腰,完全在于你使用的内存管理器和IC是否支持虚拟内存。


    从更底层一点来说,堆和栈只是对他的可见内存(可能是物理内存)的使用方式。如果我们你有1G的内存,我们可以给分256K给栈,然后拿500M给内存管理器。于是前者成了栈内存,后者成了堆内存。当然,如果你要给栈800M,对256个字节也没问题。如果我有块干净的IC和系统,所有的东西都自己起步,就可以这样干。只需要拿一块单片机系统或者直接在VC上模拟也可以。


     malloc只是标准C种实现动态内存申请的一种方式而已。它和堆内存申请并不等价。在我们自己内存管理器种,完全可以是任何名称(不考虑编程规范和接口标准的话)。



     参考与实现:
     参阅任何一本数据结构和操作系统书籍。
     参阅任何一种小的OS(uC_OS II就可以了);
     自己在单片机或者VC上模拟他们进程和内存管理。最简单的实现在函数种分配数组进行各种访问,并观察堆栈


。定一个很大数组,进行分配和回收。


   


路过

鸡蛋

鲜花

握手

雷人

发表评论 评论 (4 个评论)

访客o63Vna 2008-4-3 14:09
很专业
访客qVMx50 2008-4-4 08:12
good
liu119144664 2008-11-28 01:34
终于搞清楚数组头指针为什么不能出函数体了,非常感谢![emot]5[/emot]
lichuanbo 2009-10-12 15:45
最主要是要知道自己是个鸟还是个虫[emot]48[/emot]