转自这里:http://www.cnbeta.com/articles/121128.htm
调试iPad程序内存漏1周多了,我发现我可能不仅是在在找内存漏,而是在寻找iOS不支持多任务的原因——操作系统存在种类繁多的自泄露和内存不及时释 放。我猜测,完全利用SDK库编写的程序,如果一直在后台工作并访问网络和运行多线程的话,很难不漏内存,很难运行得长久。
看着NSAutoReleasPool和系统库的各种古怪行为,不由得感慨:“这年头,连黄瓜都靠不住了。” 关于产品发布,我猜是这样的: Apple的程序员们改不完这些bug,但产品不能再拖了,因此,帮主决定:
1、重点优化音乐播放相关的代码
2、其次重点是电话功能相关的代码(为什么这个不是第一呢?因为我嵌套猜:如果我把这个猜成第一,会被yeppy鄙视)
3、然后不允许用户程序在后台执行
4、并且教育用户:你们不需要多任务
现在iOS4出来了,估计apple程序员改了很多bug,所以,开放了一部分多任务功能,但是,iOS4的多任务推荐的后台运行模式也不是常驻运行,而是通知模式。
再过一段时间,bug改的差不多了,帮主就会穿上牛仔裤,跳上演讲台,向宇宙宣布:“革命性的革新!iPhone支持完全的多任务!你们获得了像Mac Book Pro一样强大的电话!” 肯定是这样的,“反清复明”只不过是口号,真正的目标就是银两和女人,对不对,帮主? 你把android和windows phone 7这帮兔崽子耍的团团转,是不是?哈哈!
--------------------
发文这兄弟在金山是干嘛的? :)
不过说实在的,这个很难说是最充足的理由,虽然这些技术缺陷可能帮助教主不必烦恼就做出了最后决定。Android的多任务其实也就那么回事:1、后台线程最好放在分离的Service里。2、非系统的Service有可能被杀。3、体验并不是很好。最后这个3是我觉得最要命的。比如Android的老机安装软件的时候,就非常容易卡机;而且我觉得靠硬件的进化也很难改进:总有比Killer更Killer的Killer。
多任务应该多在合适的地方,其实大数用户终端设备在绝大多数时候并不需要。其实看Windows就知道,除非你用的比较好的机器而且至少双核,否则不少软件都卡的要命。没有一个开发者会去考虑除他自己写的那点代码之外的应用的流畅性,他们总认为那是操作系统的事情。不幸的是,现在这些操作系统都落后的要命,秉承了Unix以来的设计传统,没有一个从根本上打算掌握足够的信息、用以在分配资源时能够做出正确的选择的。
而且从我个人的角度来看,应该让用户能够很容易的决定优先级(因为只有用户是可信任的,连操作系统装修商自己也有可能做出愚蠢的决定),从而保证界面和其它一些关键性的程序不受影响。这方面到底怎么安排需要一些思考工作,而且没有前人可借鉴。Apple并不是一家创新公司,从他公司创立开始,每一个点基本都是抄袭来的(比M$更甚),仅仅再包装能力确实强的没边(这也是用户的需要),在技术创新上不能指望Apple会有很快的进展。
多说一句的是,我上面的话可没有讽刺Apple的意思。哪怕一点小小的创新也是很难的。很多人都知道我自己在做一个Web框架+平台,可是就这么一个东西,从我比较有明确目的开始做到现在,3年以上都过去了吧,刨除中间断断续续玩别的的时间大概一年,也不过,按我自己的话说,“刚看见起点”,有几个简陋不堪的界面,核心仅仅能够最初步的表达我的很少一部分理念,能体现出来的创新也不多。
这些年对于各个部分的设计和实践,做了废废了做,来回实验的全部代码得按6位数计了,可最终留下的又有几行呢?Apple并不会因为规模比我大得多,就比我快得多:做决定的永远是少数人,其它人只能一边领工资、一边等着。越是大公司越不能承受一次性跨越的成本。
另外一个关键是现在好的程序员越来越少,虽然开发人员很多,有些也很棒,但毕竟只是开发人员。不是说开发人员就不知道统筹安排,不知道cache变量、减少循环之类的技巧,也不是没有细心检查、防止内存泄露的心思;关键是开发人员大多数不具备真正的抽象能力,不能快速识别问题的共性和泛化解决方案(我自己做的也不好,更何况大型团队还有个配合问题),这样导致每一个问题都转化为工作量,对于已经很大型的软件工程来说,最终就是不能承受的软件发布期限。
上面说到软件卡、启动速度慢,比如我PD820,在我看来很多时候不是没有优化的空间。比如FireFox在Windows上的启动速度,你有什么屁东西非得在启动时搞半天的?比如VS2010的JS智能提示,居然比Python的WingIDE都慢,干什么吃的?如果这些级别的软件公司其开发人员都这样,说实话唯一的指望确实仅剩下硬件的功耗比了。
关于这位兄弟提到的内存泄露问题,很多Java/.NET的兄弟可能又想起垃圾回收来了。在这里我真心说一句,不是特意为自己程序配置过的垃圾回收,也就是说我们现在用的这些通用的垃圾回收,本身就是垃圾。关键是它在你的项目里也许还不那么臭,比如许多服务器上跑的应用看不出来,但在一个被频繁操作的资源受限设备上就绝对的明显了。所以这实际上是一个何时/选择什么方案的问题;在移动设备上,我暂时支持Apple。
Update:似乎又是骂街,没有提建设性方案。这个要改,不然跟就知道嚷嚷的SB没什么区别。
.NET/Java如何解决垃圾回收问题,又不面临内存泄露、同时避免引用计数和快速申请释放时候的性能损耗?很简单,a: 写专门针对该项目的内存分配器,这非常简单,因为你很清楚什么时候为什么目的要用多少内存,哪些应该重用、哪些可以释放。b: 写更高级的通用分配器,但是可以根据你最关心的一些问题定制,这个要考虑的量一下就要上升好几倍,谨慎。
分配器、运行时和使用接口之间的具体结合方法,.NET:C++/CLI,Java:JNI。当然,要想好用,反射是少不了的了。
而任务优先级的问题嘛....,肯定不可能重写操作系统了。拿*nix系来说,内核做一个驱动让用户空间可以注册,然后实现一个自己的分配机制;提供一个界面给用户,或者使用一些更“智能”的判定方式。具体的东西,嗯我还真说不出来;因为我现在的判断是这种级别的mod一定要小心翼翼,可能造成的问题我却还没考虑过。
不过我注意好像.32内核带一个给进程分group的东东?也许可以参考或者拿来。最关键的是简洁,不能咱弄个特复杂的算法,反而让CPU跟降频了10%似的;即便用户注意不到,电还是一样要废的。
当然,要是组织中没人承担开发这个的成本(比如你干这个去了,其它的活儿谁干,重构的成本,等等),一切休提。
Update2: 把我上次要唠叨但没发的关于垃圾回收的一个主题的核心观点说说。指针的扩散,乐观地说90%的情况下是有迹可寻的,一个编译时的工具足够检查出大多数new了不delete之类的情况。所以内存泄露的危险是垃圾回收的理由,这一点完全不成立。
对于优化内存申请/释放频率来说,上面已经提到了特定的方法。即使不使用上述方法,也可以实现通用的带缓存的回收器。有人说那这和垃圾回收不一码事了么?当然不是,虽然有检查器和分配器,但我们仍然要求程序员明确的声明内存什么时候用不着(甚至可以自动在传播的最后一个位置通过运行时代码生成插入delete),有了更完善的信息,自然更加精准高效。
实际上,我这几年来发现的所有软件领域的问题,无论是蹩脚的设计、还是bug或者运行效率,基本上都是由于必要信息在软件构建、使用的各个过程中不断损失所造成的。这是一个远超当前各个方法论提倡的东西的核心问题,甚至超越了软件开发本身。如果还没有有影响力的组织或直接或间接的解决这一问题,银弹(相对的)就不太可能会出现了。
但至少的,我们可以在自己的项目中注意这个问题,虽然使用现阶段能找到的思维(方法论)和实践工具(语言等编程工具)来维护信息,其代价似乎有点高。