new 出来的存储空间(如果不使用delete),系统会自动回收?

http://blog.sina.com.cn/s/blog_4aecb7bd010006gb.html

 

new 出来的存储空间(如果不使用delete),系统会自动回收?!

 (2006-11-12 11:41:12)

转载

 

分类: 编程语言C

  : Re: new出来的空间系统会不会自动回收?
发信站: BBS 哈工大紫丁香站 (Sat May 15 09:25:05 2004)

  
 看见N本书这样说过,对于现代操作系统而言,是可以不delete,其实new操作到最后会被编译器链接到malloc上,是调用的malloc,而malloc是一个系统调用,用来分配内存。因此,内存的分配最终是由操作系统而不是由编译器完成的,编译器只是起个调用系统调用以分配内存的的动作,而真正怎么分配是由操作系统决定的.

一般操作系统都有一块很大的自由内存区,这块自由内存区也称为堆,当你用new分配这块内存的时候,也被称为在堆上分配,当你用new产生一个操作系统调用,要求分配内存的时候,操作系统就检查这块堆,检索出一块大小合适的且被标记为未分配的内存,并返回它的指针,然后再把这块内存标记为可分配,当你调用delete的时候,操作系统再清除这块内存的可分配标记,以便可以再次分配这块内存。这就是一个最最简单的内存分配动作,打个比喻,操作系统就像银行,new就像你向银行借钱打个借条,delete就像你还钱的时候,银行取消掉借条.以前还有问,为什么在delete后,还可以操作这块内存,而不出现段错误?从上面的描述中可以看出,delete后的内存还是在内存空间中,只是重新被操作系统标记为可分配了,因此你当然还可以对其进行操作,只不过,你并不知道它在什么时会被分配出去,如果它被分配出去了,你对此块内存的操作就非常危险了。

   
 当然,一个健壮的操作系统完全可以在你访问不属于你的内存时(或者访问被标记为"可分配"的内存时),产生一个错误中断或错误陷阱,这主要看操作系统的怎么管理的了。一个非常健壮的操作系统也许会检测所有对堆内存的访问,如果发现你访问了一块不是你的内存,就会出错。而这样的检测是比较费时间的,因此,有些操作系统可以选择只对已分配的内存进行这样的检测,于是,在此块内存被delete重新标记为可分配到被重新分配前,你可以继续对此内存进行操作,而一旦此内存被重新分配出去,内存标记表为已分配,这时,你再继续使用这块内存时,操作系统就会报错了。这样,有时后你访问已delete的内存时,不会出错,而有时又会出错,这就是由于在先前这块内存还未被分出,操作系统不检测你对此内存的访部是否合法,因此没出错,但下次你再访问时,这块内存已被分给其它进程使用了,因此,操作系统会对这个内存进行检测,于是就出错了.

 

 

    对于一些采用页式管理的操作系统,最底层的内存分配一次分配一页(4KB),然后在其上实现一层高级内存管理,以便用你可以分配指定大小的内存而不是一整页了,当一页上的所有空间全部被delete,即全部标记为可分配时,操作系统就会将这页的存在标记置为不存在,然后将其从内存中去除,并在页表中去除,这样,当重新访问时,CPU会产生缺页中断,操作系统会对这样的中断进行处理,处理或许是会重新载入此页,或许是产出一个错误,因为操作系统发现你已经delete了,无权再访问此页了,要访问,你需要重新new.

 

    因此,这就会出现一个非常有趣的现象:你delete了一块内存,然后不停的访问,前99次都可以,而第100次就不行了,这或许就是因为前99次时,因为此页上还有其它进程没有delete的空间,而第100次时,其它进程洽好全部delete了,于是操作系统把此页作废了,你再访问时,操作系统就会发现你是非法访问,于就就出错了。因此,99次运行正确的程序,不见得第100次运行就会正确!这样做的好处就是,操作系统只在产生缺页中断的时候,才检测内存访问是否合法,由于内存访问是很频烦的操作,降低检测次数,当然就可以系统效率升高。操作系统在分配内存时,会建立一个数据结构,对一块已分配的内存保留它的很多信息,比如这块内存的首地址,大小。因此,才会有这样一种显象,当mallocnew一块内存时,你需要指定要分配的内存大小,而当你freedelete时,却不需要指定大小,而只需给出内存的首地址指针就可以了,这主要是因为,操作系统只需要把这块内存重新标记为可分配,而其内存大小,在操作系统分配内存时,操作系统就自动把它记录下来了。

   
 现代操作系统,在分配内存时,还会记录内存被分配给哪个进程了,这样,当进程在退出的时候,就完全可以强制性回收所有的分配给这个进程的空间。当然,如果一个操作系统在分配内存时,并没有记录这块内存并分配给谁了,那么它就不能强制回收一块内存,这时就需要你必须用delete。这样的情况主要出现在古董级的操作系统上,因为当时的内存非常有限,不允许操作系统如此大方的用它来存储它需要存储的信息,不过,对于现在来说,保存一下内存被分配给那个进程了实在是小case,因此,现在你可以不太注意是否使用了delete了,不过用delete会及时的释放内存空间,但不用delete,却只会在进程完蛋时才释放,这其间的区别,自然就不用多说了。

   
 不过我想提醒一下,操作系统强制回收不等于我们常常说的垃圾回收机制!,看看java,它的垃圾回收机制,它是先不断的分配内存,只要能分配就分配,如果不能分配了,它再查找一下哪些内存已经不被程序使用了,它就回收它,但操作系统强制回收机制却没有这样的能力,它不知道哪些内存已经不被程序使用了,对于它而言,只要是没有delete的内存,它就认为程序还在使用它。说简单一点,对于javaC两个程序,如果都只用new而不用delete,那么java可以在程序运行的过程中就回收内存,而c的程序却不行,只能在程序运行结束后,由操作系统一次性强制回收,java是边用边收,程序可以永远运行,而c是只用不收,当最后没有再能用的时候,程序不得不被杀除,这时操作系统再回收,于是,如果你在java中用for(;;)new...java程序可以一直运行下去,而c却总用内存用尽的时候。

   
 那么是否是所有的new,都可以不delete呢?这也不见得,有的操作系统会在内存分配的时候,除了保留内存分配的指针及大小外,还要保留一个类型参数,用来标记这个内存是进程单独使用,还是多进程共用。如果是单独使用,当然可以在进程结束时,由操作系统自动回收;如果是多进程共用,这当然就不行了,因为,此进程虽然结束了,但还有进程在使用,因此不能回收。在多进程共用内存的分配上,这很大可能是由引用计数实现的,每块内存都有一个引用计数值,最初的引用计数值是0new一次就+1delete一次就-1,只有当其值为0时,才会被操作系统真正回收,这时,如果你new了,但没有delete,则引用计数就不可能成为0,这块内存就会一直被保留,而无法被操作系统回收,这种情况下,你就必须在newdelete了。

   
 内存的分配是由操作系统完成的,而不是由编译器完成的,mallocnew等等,只是一个系统调用,它调用操作系统的内存分配函数来完成内存分配的功能,而具体怎么分配是操作系统决定的,编译器无法决定,也无法知道,因此,这是平台相关,而编译器无关的。

   
 各个操作系统对于内存分配的策略各有不同,反正是CPU就提供了那些功能,在这些功能上,怎么实现以满足需求是八仙过海,各显神通,这没有参考资料,也没有标准答案,linux为了满足它的需求,采用了一种实现方式,而windows为了满足它的需要,采用了另一种实现方式。像pyos,我的想法是提供一个功能更强一点的内存管理,比如,一个进程可以申请分配一个共享内存区,而只有申请分配的内存具有写权限,而其它进程只具有读权限,这又是另外一种内存分配策略。我想我们可以提出一个需求,然后讨论可以用什么方法实现这样的需求,可以讨论linuxwindows为什么要这样实现,而不是讨论linuxwindows怎样实现,不是讨论应当怎样实现,或者去讨论书上说怎样实现。

原文:http://purec.binghua.com/Article/ShowArticle.asp?ArticleID=130

 

文章引用自:http://blog.csdn.net/xiaohan13916830/archive/2004/06/30/30102.aspx

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值