不管什么样的编程语言,在代码的执行过程中都是需要给它分配内存的,不同的是某些编程语言需要我们自己手动的管理内存,某些编程语言会可以自动帮助我们管理内存。
不管以什么样的方式来管理内存,内存的管理都会有如下的生命周期:
- 第一步:分配申请你需要的内存(申请)
- 第二步:使用分配的内存(存放一些东西,比如对象等);
- 第三步:不需要使用时,对其进行释放;
不同的编程语言对于第一步和第三步会有不同的实现:
- 手动管理内存:比如C、C++,包括早期的OC,都是需要手动来管理内存的申请和释放的(malloc和free函数);
- 自动管理内存:比如Java、JavaScript、Python、Swift、Dart等,它们有自动帮助我们管理内存;
垃圾回收
垃圾回收器:Garbage Collection,GC.对于那些不需要使用的对象需要回收、占用的内存需要释放。
那么GC是怎么实现判断哪些对象需要回收呢。GC概念最早出现在Lisp
引用计数(Reference counting)
当一个对象有一个引用指向它时,那么这个对象的引用就+1;当一个对象的引用为0时,这个对象就可以被销毁掉;
这个算法有一个很大的弊端就是会产生循环引用;
标记清除
标记清除的核心思路是可达性(Reachability)。
这个算法是设置一个根对象(root object),垃圾回收器会定期从这个根开始,找所有从根开始有引用到的对象,对于哪些没有引用到的对象,就认为是不可用的对象。
这个算法可以很好的解决循环引用的问题。
JS引擎比较广泛的采用的就是可达性中的标记清除算法,当然类似于V8引擎为了进行更好的优化,它在算法的实现细节上也会结合一些其他的算法。
标记整理(Mark-Compact)
标记整理(Mark-Compact)和“标记–清除”相似;不同的是,回收期间同时会将保留的存储对象搬运汇集到连续的内存空间,从而整合空闲空间,避免内存碎片化;
分代收集(Generational collection)
对象被分成两组:“新的”和“旧的”。
- 许多对象出现,完成它们的工作并很快死去,它们可以很快被清理;(检查频率高)
- 那些长期存活的对象会变得“老旧”,而且被检查的频次也会减少;
增量收集(Incremental collection)
如果有许多对象,并且我们试图一次遍历并标记整个对象集,则可能需要一些时间,并在执行过程中带来明显的延迟。
所以引擎试图将垃圾收集工作分成几部分来做,然后将这几部分会逐一进行处理,这样会有许多微小的延迟而不是一个大的延迟;
闲时收集(ldle-time collection)
垃圾收集器只会在CPU空闲时尝试运行,以减少可能对代码执行的影响。