摘要:基于某些机制实现半自动管理这里的某些机制其实通常就是引用计数。早年,选择的是退一步,完全让程序员来管理引用计数的加减,称为,显然管理成本偏高。
概述
应用程序开发中,内存管理是个重要的话题。
简单而言,语言层面的内存管理基本有三类:
如C和曾经的C++。
char *some_string = malloc(BUFFER_SIZE); // do something free(some_string);
这个简单的例子里用完就释放还好,但是有时候这个some_string被传来传去不知道飞哪儿去了,就比较尴尬。
纯手动管理的代价是程序员的心智负担比较重。
即使后来C++程序员们抽象出RAII这样的实践规范,一定程度上降低了管理的复杂度,但是相对来说成本还是略高。
随着语言的发展,已经很少有语言只依赖手动管理内存了。
这里的某些机制其实通常就是引用计数。毕竟这是最简单的内存管理辅助手段。
引用计数是计算机编程语言中的一种内存管理技术,是指将资源(可以是对象、内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的过程。
引用计数大家都了解,不多说,单纯的自动使用引用计数问题在于无法解决循环引用的问题。很多语言选择让程序员付出一点劳动来解决这个问题。
早年,Objc选择的是退一步,完全让程序员来管理引用计数的加减,称为MRC,显然管理成本偏高。后来推出了ARC,提供了更健全的机制,程序员只要标识出对象间的引用关系是强引用还是弱引用就可以了,大大降低了程序员的负担。
虽然走这个路子的语言不算多,但除了Objc之外还是有好几个的。
C++的智能指针跟Objc的ARC就比较相似。而Rust的所有权模型本质上也是类似的。
通过GC自动管理内存大概是现在的主流了。对程序员来讲实在是太舒适了,开发时几乎不用考虑内存管理的问题。Java、JavaScript、Python、go等一大票语言都是走的这条路。
GC是基于可达性分析算法的,即,从根节点(全局变量、局部变量等等)出发,遍历引用到的对象,所有没遍历到的对象就可以释放了。
当然从原理到实际应用中间差了十万八千里。朴素的GC会经常造成Stop The World。一旦Stop-the-world发生,除了GC所需的线程外,其他线程都将停止工作,中断了的线程直到GC任务结束才继续它们的任务。
于是很多GC算法被发明出来用于优化、减少。常见的CMS、G1回收算法都极大地减少了STW的时间,但仍然不能完全避免。
R大在Java 大内存应用(10G 以上)会不会出现严重的停顿?中提到Zing JVM采用的C4算法是可以完全避免STW的,不过看起来为了避免STW,C4算法会吃掉更多的内存,程序吞吐量会受到影响。
总结一下吧,纯手动管理基本上已被淘汰,ARC(暂且把方法二这类都称为ARC吧)和GC对比之下,
对开发者,ARC需要程序员付出一定的代价进行管理,GC则基本上完全解放双手;
性能上,GC通常会造成STW现象,对响应时间比较敏感的程序,比如高频交易系统,是很难接受的,而ARC不会对性能造成明显影响。
总体性能上,只要不是内存跑得特别满,ARC的总体代价是高于GC的。其实想想就知道了,GC只关注两次回收间的变化,而ARC要对每一次引用的改变进行计数,总体性能上比GC差是很正常的,但由于ARC的耗时是均匀分布在运行时间里的,通常我们不用很关注。关于这个问题可以参考这篇论文。
2. cpython的方案另外比较特别的是,Python的默认解释器CPython中应用了引用计数与垃圾回收相结合的手法,没有循环引用的对象会被引用计数回收,剩下的交给GC处理,大大降低了GC的压力。感觉很有意思。
3. ARC的性能在类ARC方案上,C++提供的能力是比较全面的。这可能跟c++常用于一些性能比较苛刻的场景有关。
出于性能原因,使用c++智能指针时有如下指导思想:
对象的所有权不重要时 ,用裸指针
对象的所有权唯一时,用unique_ptr,能用unique_ptr就不要用shared_ptr。
要处理复杂情况时,可以使用shared_ptr,但需要注意不要滥用。当引用关系不影响所有权时,用weak_ptr。
Rust也有类似的能力。
而python和Objective-C就没有这么多讲究,所有的引用计数其实都是shared_ptr。Objc在iOS上这么多年,而后来的swift也传承了ARC,基本上可以认为,移动端应用从小到大都不差这么一丢丢性能。
以此推论,绝大部分c++应用也完全没必要关注这几个指针间的差异,操起shared_ptr就是干。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/17295.html
摘要:早期引用计数的内存管理继承自,拥有一套基于对象引用计数的内存管理体系。这种引用计数的思想在很多地方也有应用,不过本质上说,仍然是需要程序员来手动管理计数的,只不过当计数值清零时,对象会被自动释放罢了。 原文:Objective-c 内存管理的历史和参考资料 对于像我这样自学IOS开发的初学者,网上有很多资料,很多教程,但是过于多的资料也使初学者无法筛选合适自己的。并且Objectiv...
摘要:成长年,和成立了公司,并发布了第一个实现。动态语义是通过一个来实现的,这个逐渐发展成了现在的简称。将这一新的实现称为,也就是我们现在看到的这个样子。困难之一是与和之间的协调。但最终克服了重重障碍,成为管理依赖的首选。 showImg(https://segmentfault.com/img/remote/1460000006768947); 文 / 唐天勇 LeanCloud 工程师 ...
摘要:在里,每个继承自的对象都会记录自身的引用计数,一番加加减减之后,变成就会释放掉。引用计数减少的操作就是了。要知道,返回的对象引用计数是有的,而并不是。 罗里吧嗦颠三倒四,单纯的个人笔记。 MRC 引用计数上一篇已经有大概讲过。在Objective-C里,每个继承自NSObject的对象都会记录自身的引用计数,一番加加减减之后,变成0就会释放掉。MRC是Mannul Reference ...
摘要:本文将从设计模开发封装掘金前言很久以前,手机的性能取决于处理器的处理速度。对于要求苛刻的苹果竟然在如此简单的使用调试掘金一概述全称默认内置于中的动态调试工具。 iOS 开发 - 多线程陷阱 - iOS - 掘金前言 随着手机硬件的升级,多线程技术在应用开发中的地位可以说足以媲美UITableView了。然而,多线程技术在提供我们生产力的同时,也不可避免的带来了陷阱,正如著名计算机学者所...
摘要:本文将从设计模开发封装掘金前言很久以前,手机的性能取决于处理器的处理速度。对于要求苛刻的苹果竟然在如此简单的使用调试掘金一概述全称默认内置于中的动态调试工具。 iOS 开发 - 多线程陷阱 - iOS - 掘金前言 随着手机硬件的升级,多线程技术在应用开发中的地位可以说足以媲美UITableView了。然而,多线程技术在提供我们生产力的同时,也不可避免的带来了陷阱,正如著名计算机学者所...
阅读 1540·2021-11-22 09:34
阅读 957·2021-09-28 09:35
阅读 2706·2021-09-28 09:35
阅读 11950·2021-09-09 11:34
阅读 2177·2021-09-08 09:36
阅读 3449·2019-08-29 16:25
阅读 2627·2019-08-29 15:23
阅读 1910·2019-08-28 17:55