回复: 请教各位大大关于动态内存管理的问题…… 说道优化,有个题外话:我一直到最近才明白,程序的优化,首先是针对人的资源的优化,其次才是针对机器的优化。首先要优化的就是尽量少占用人的资源,让人更容易理解、把握,占用人尽量少的脑力、时间和精力,哪怕为此多花一些机器时间也是值得的,毕竟无论是程序开发人员,还是软件使用者,他们的脑力资源比机器的资源更宝贵。
就针对机器的优化来说,我一直坚持,如果一种优化会使程序员对程序的掌控减弱,那么就是不合算的。
手动调用gc的collect,恐怕也不能频繁地这么做吧,毕竟频繁扫描内存的话代价还是很高的。至于“本来应该自己管理的资源”,这个我还不清楚怎么界定。毕竟内存也可以说是“本来应该自己管理的资源”,毕竟程序员要对程序负最终的责任,如果内存管理出问题,责任不会落在gc头上。我只是觉得,如果把gc看作多种管理手段之一,由于它的不确定性(在怎么样可控性也比内存池要差),以后的优化会受到负面影响。
智能指针的释放“时间”自然是由runtime决定的,甚至根本上说释放“时机”也是由runtime决定的,而后者正是不得不使用智能指针的原因。但是另一方面,我知道当没有指向这个对象的指针时这个对象一定会立刻被释放,而使用gc时我不知道是否会这样。如果需要我手动collect,那我不如使用内存池。如果我不能使用内存池,那么意味着我即使使用gc,我也很难知道应该什么时候collect,因为释放的“时机”是由runtime决定的。
一个对象的释放引起大量对象释放的问题,其实gc也有,毕竟本质上gc也是靠“对象是否被需要”来判断是否应该回收的,只不过gc没有智能指针里那么多析构函数调用的开销,但是gc有一些开销是智能指针所没有的,毕竟扫描内存,比如线程切换,而且当gc扫描一块内存时应用程序自然无法再使用这块内存。
其实我最关心的是,我是否知道我所采用的技术到底在干什么。其次才是对象如何以及何时被销毁。
对于内存池和gc之间的选择,我也会优先选择内存池,就像我顶楼里写的,我心中的优先次序是:
栈>内存池>智能指针>gc
能用栈我就不用内存池,能用内存池我就不用智能指针,能用智能指针我就不用gc,只有其他都不能用的时候我才选择gc。但是,gc有个特别的地方就是,它的表达能力近乎无限。栈和内存池其实都对内存的时候有着各自的“假设”,所以当我需要一个对象的生存期跨越栈时,如果不让它升到更高层的栈,那么就会打破栈的使用假设,内存池也一样。对于gc,如果不考虑性能,只考虑“能不能”的问题,那么我还不知道有什么情况是无法应用gc来表达的,只不过性能和确定性等问题使gc在我心中的地位排到了最后。如果gc既有现在的表达能力,又有栈的性能,而且在需要的时候我能够容易的预知它的行为,那么我就会把gc放到第一位了。 ^_^!
其实,如果gc的释放时机能够达到智能指针的确定程度,那么我就会把gc放到智能指针的前面。如果要靠手工collect,那么不如换成内存池。
关于隐藏的问题。我觉得,良好的设计应该是有透明性的,也就是说加入这个技术之后,它自己会做一些事情,但是我不需要知道它做了什么,但是更重要的是,我原来知道的事情,在加入之后我仍然知道,而不会被新技术挡住视野。就像玻璃窗,它能帮我挡风遮雨,但是我仍然能看到窗外的景色。
如果内存真的是不需要关心的问题,那么隐藏起来也无所谓,但是恰恰相反,尽管现在的内存越来越大,但是内存仍然是常常不够,一方面是因为人的需求在不断增长,当硬件的处理能力提升了10%时,人的期望却可能提升20%,所以我从来不认为硬件资源会“足够”,另一方面,延后释放会加剧对内存的需求。所以内存管理决不是程序员可以放手不管的事情,除非gc真的具有了程序员那样的智慧。
而CPU的优化,其实在很多时候仍然会需要使用汇编进行优化,而现在很多程序都在引入一些多媒体技术来改善用户交互,所以CPU使用的优化也不是程序员可以放手不管的问题;而乱序执行和寄存器使用的优化恰恰使得多线程程序(特别是多核机器上的多线程程序)更难编写,所以C++09才需要做出一些限制。虽然我对多线程不是很推崇,但是它毕竟是多核时代优化的重要手段。
其实,如果需求是一成不变的,那么很多隐藏都不会带来太大的问题,毕竟如果它过去能生存下来,那么以后也能。但是当需求经常会变的时候,一项技术过去运行得再好也不能说明以后会怎样。而当需求变了,我们却发现很多东西都被层层遮盖起来,这时我们要适应需求的变化就会有更多的阻力。人对程序的了解越多,那么就越容易适应变化。 |