新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → 内存分配深入探讨 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 16524 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 内存分配深入探讨 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客楼主
    发贴心情 内存分配深入探讨

    摘要:内存管理向来是C/C++程序设计的一块雷区,大家都不怎么愿意去碰她,但是有时不得不碰它。虽然利用C++中的smart pointer已经可以完全避免使用指针,但是对于对于指针的进一步了解,有助于我们编写出更有效率的代码,也有助于我们读懂以前编写的程序。
        五大内存分区
        在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
        栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。
        堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
        自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
        全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
        常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多,在《const的思考》一文中,给出了6种方法)
        
        明确区分堆与栈
        在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以我决定拿他第一个开刀。
        首先,我们举一个例子:
        void f() { int* p=new int[5]; }
        这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下:
        00401028   push        14h
        0040102A   call        operator new (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是保留在虚拟内存的页文件里面,它设置的较大会使栈开辟较大的值,可能增加内存的开销和启动时间。
        碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。
        生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
        分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
        分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。
        从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。
        虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,还是用堆好一些。
        无论是堆还是栈,都要防止越界现象的发生(除非你是故意使其越界),因为越界的结果要么是程序崩溃,要么是摧毁程序的堆、栈结构,产生以想不到的结果,就算是在你的程序运行过程中,没有发生上面的问题,你还是要小心,说不定什么时候就崩掉,那时候debug可是相当困难的:)
        对了,还有一件事,如果有人把堆栈合起来说,那它的意思是栈,可不是堆,呵呵,清楚了?

       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/2/8 8:59:00
     
     blackiron 帅哥哟,离线,有人找我吗?
      
      
      等级:大一新生
      文章:1
      积分:61
      门派:XML.ORG.CN
      注册:2006/3/10

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给blackiron发送一个短消息 把blackiron加入好友 查看blackiron的个人资料 搜索blackiron在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看blackiron的博客2
    发贴心情 
    错了吧!!!
    “堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。”

    如果不用delete 操作系统会自动回收内在的话,就不会存在内存泄漏一说了!!!

    大哥,你搞清楚再说啊,看到这里就不想再看了

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/3/10 23:39:00
     
     bood 帅哥哟,离线,有人找我吗?
      
      
      等级:大一新生
      文章:3
      积分:70
      门派:XML.ORG.CN
      注册:2005/3/18

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给bood发送一个短消息 把bood加入好友 查看bood的个人资料 搜索bood在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看bood的博客3
    发贴心情 
    这就是你的不对了,一般确实都会被操作系统回收
    泄露不泄露说的是被os回收以前
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/3/11 0:21:00
     
     sevencat 帅哥哟,离线,有人找我吗?
      
      
      等级:大一新生
      文章:11
      积分:100
      门派:XML.ORG.CN
      注册:2006/2/14

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给sevencat发送一个短消息 把sevencat加入好友 查看sevencat的个人资料 搜索sevencat在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看sevencat的博客4
    发贴心情 
    OS会自动回收的(不过听说有些是有问题的)
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/3/12 13:12:00
     
     onlyxuyang 帅哥哟,离线,有人找我吗?
      
      
      等级:大一(猛啃高等数学)
      文章:12
      积分:123
      门派:W3CHINA.ORG
      注册:2006/6/1

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给onlyxuyang发送一个短消息 把onlyxuyang加入好友 查看onlyxuyang的个人资料 搜索onlyxuyang在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看onlyxuyang的博客5
    发贴心情 
    以下是引用blackiron在2006-3-10 23:39:00的发言:
    错了吧!!!
    “堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。”

    如果不用delete 操作系统会自动回收内在的话,就不会存在内存泄漏一说了!!!

    大哥,你搞清楚再说啊,看到这里就不想再看了


    内存泄露指的是程序在运行的过程中可用内存越来越少,少到极至机器就会当掉.
    一般程序内存泄露都看不出什么故障的,因为就算泄露了程序关闭以后OS会回收掉。
    但是对于那种必须常时间工作的程序来说内存泄露就很要命了,比如象数据库.Web服务器和路由器等等必须长时间(有时候甚至要求1年的间断时间不能超过1个小时)运行,要是存在内存泄露的话,一点一点的泄露,过不了多久机器就当掉了。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/6/2 0:50:00
     
     flyfoxs 帅哥哟,离线,有人找我吗?
      
      
      威望:5
      等级:研一(Artificial Intelligence期期不放过)
      文章:550
      积分:3935
      门派:XML.ORG.CN
      注册:2005/1/8

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给flyfoxs发送一个短消息 把flyfoxs加入好友 查看flyfoxs的个人资料 搜索flyfoxs在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看flyfoxs的博客6
    发贴心情 
    看了上面的东西,有如下理解不知道对不对.

    就是平时写的玩的程序,内存泄露问题不大,只要程序关了之后,泄露的空间会被OS回收.

    也就是电脑时如果发现有内存泄露现像了,肯定是由于现在OS还在运行的程序造成的.不关别的程序的事.

    ----------------------------------------------
    存在即是被搜索!

    BLOG =>  http://www.OpenJ.cn

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/11/17 11:03:00
     
     wcdxyl 帅哥哟,离线,有人找我吗?天秤座1980-10-9
      
      
      威望:4
      等级:大四(每天看1小时莱昂氏)(版主)
      文章:158
      积分:1145
      门派:IEEE.ORG.CN
      注册:2006/3/14

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给wcdxyl发送一个短消息 把wcdxyl加入好友 查看wcdxyl的个人资料 搜索wcdxyl在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看wcdxyl的博客7
    发贴心情 
    我也来说两句,首先楼主总结得不错,2楼的没明白楼主的意思,
    楼主没有说操作系统一定能回收完全。所以只靠系统回收是有风险的,可能造成内存泄漏。

    对5楼说:内存泄漏和程序运行的时间长短没关系,而是和造成泄漏的程序部分调用的次数有关系。

    ----------------------------------------------
    主页:http://wcdxyl.blogchina.com
    MSN:wcdxyl@163.com

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/11/17 18:03:00
     
     flyfoxs 帅哥哟,离线,有人找我吗?
      
      
      威望:5
      等级:研一(Artificial Intelligence期期不放过)
      文章:550
      积分:3935
      门派:XML.ORG.CN
      注册:2005/1/8

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给flyfoxs发送一个短消息 把flyfoxs加入好友 查看flyfoxs的个人资料 搜索flyfoxs在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看flyfoxs的博客8
    发贴心情 
    以下是引用wcdxyl在2006-11-17 18:03:00的发言:
    我也来说两句,首先楼主总结得不错,2楼的没明白楼主的意思,
    楼主没有说操作系统一定能回收完全。所以只靠系统回收是有风险的,可能造成内存泄漏。

    对5楼说:内存泄漏和程序运行的时间长短没关系,而是和造成泄漏的程序部分调用的次数有关系。


    是不是程序退出后,这个程序泄漏的内存肯定会被回收?

    如果不是的话,什么情况下不会被回收?

    ----------------------------------------------
    存在即是被搜索!

    BLOG =>  http://www.OpenJ.cn

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/11/18 12:39:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客9
    发贴心情 
    以下是引用flyfoxs在2006-11-18 12:39:00的发言:
    以下是引用wcdxyl在2006-11-17 18:03:00的发言:
    我也来说两句,首先楼主总结得不错,2楼的没明白楼主的意思,
      楼主没有说操作系统一定能回收完全。所以只靠系统回收是有风险的,可能造成内存泄漏。------对,如果程序运行中由于内存泄漏导致内存不足程序就崩溃了。

      对5楼说:内存泄漏和程序运行的时间长短没关系,而是和造成泄漏的程序部分调用的次数有关系。------5楼说的也对,有一种情况就是线程等反复new小空间,时间长了当然泄漏的也就更多了。


    是不是程序退出后,这个程序泄漏的内存肯定会被回收?
    -----------一般该程序正常退出后,操作系统都会根据它所new的一一回收的,但是由于异常退出,有可能导致分配内存的进程没有结束,它还是一直在泄漏内存,操作系统并不认为该内存应该回收,那么程序退出后就不被回收了----病毒原理的一种。
    如果不是的话,什么情况下不会被回收?
    -----------上面说的,机器会越运行越慢,最终会导致系统崩溃。


    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/11/18 16:13:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/11/26 15:01:21

    本主题贴数9,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    4,531.250ms