首页 > 代码库 > C++代写,C++作业代写,代写C++,编程代写(微信leechanx)

C++代写,C++作业代写,代写C++,编程代写(微信leechanx)

C++代写,C++作业代写,代写C++,编程代写(微信leechanx)

 

主要的GC算法

     
     三种基本方法:标记清除法、复制收集法、引用计数法
   高级方法:分代回收法
 
一、标记清除法
 
标记阶段:先从根对象开始,以深度遍历的方式对其可达的对象(A可达对象B的意思是:A引用了B)标记,表明这些对象是存活的;
清除阶段:对未标注的对象进行空间回收,同时将所有已标记的对象清理标记状态,为下次标记做准备。
 
大致过程:
 
内存空间状态:
技术分享
 
 
缺点:
(1)标记-清除算法的比较大的缺点就是垃圾收集后有可能会造成大量的内存碎片,像上面的图片所示,容易引发OOM(out of memory),比如还要申请3个单元的内存,没连续空间了~
(2)当有大量对象,而其中只有一小部分存活,那么标记和清除的时间消耗很不值得。
 
二、复制收集方法
改进了两个Mark and Sweep的上述两个缺点
 
它将可用内存容量划分为大小相等的两块,每次只使用其中的一块。当这一块用完之后,启动GC,将还存活的对象复制到另外一块上面(而且是连续地复制),然后在把已使用过的内存空间一次理掉。这样使得每次都是对其中的一块进行内存回收,不会产生碎片等情况,只要移动堆订的指针,按顺序分配内存即可,实现简单,运行高效。
过程大致如下:
技术分享
内存空间变化如下:
技术分享
 
优点:有效解决了内存碎片
缺点:内存缩小为原来的一半。
 
三、引用计数方法
优点: 原理简单,方便,容易实现,对象在失效瞬间就可以被回收;
缺点:最大缺点在于无法处理“循环引用”问题,造成内存泄露;此外,并行操作比较麻烦,要同步ref_count;
 
以上三种方式是基本,大部分高级GC是离不开这三种基本方式的。
 
四、高级GC方法:分代回收方法
 
由于GC与程序本身无关,所以其引发的时间消耗越短越好,为尽量减少GC消耗时间,出现了分代回收方法
基本核心:
程序一般特性是,大部分对象会在短时间内会成为垃圾,而经过一定时间仍然存活的对象往往具有较长的寿命。如果对诞生时间较短的年轻对象进行重点扫描,而对诞生时间较长的对象尽量少扫描,就可以减少时间并有效回收大部分垃圾。
 
基本思路:
对象按照生成时间进行分代,刚出生不久的年轻对象划分到年轻代;存活了较长时间的对象划分到老生代;
 
先Minor GC(小回收):扫描新生代对象进行GC(一般是采用 复制收集 方法),
经过一定次数的GC后,将仍然存活的对象放置到老生代。
 
再Major GC:当老生代对象达到一定数量后,扫描老生代对象进行GC。
 
一般多次的Minor GC后才有一次Major GC。
整个GC过程大大减少了扫描对象的规模。
 
以JVM分代回收机制为例详细:
 
如何分代
 
技术分享
 
如图所示:
虚拟机中的共划分为三个代:年轻代(Young Generation)、年老点(Old Generation)和持久代(Permanent Generation)。其中持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系不大。年轻代和年老代的划分是对垃圾收集影响比较大的。
 
年轻代
年轻代是所有新对象产生的地方。当年轻代内存空间被用完时,就会触发垃圾回收。这个垃圾回收叫做Minor GC。年轻代被分为3个部分——Enden区和两个Survivor区。
 
年轻代的几个要点:
大多数新建的对象都位于Eden区。
当Eden区被对象填满时,就会执行Minor GC。并把所有存活下来的对象转移到其中一个survivor区。
Minor GC同样会检查存活下来的对象,如果需要会把它们转移到另一个survivor区。这样在一段时间内,总会有一个空的survivor区。
经过多次GC周期后,仍然存活下来的对象会被转移到年老代内存空间。通常这是在年轻代有资格提升到年老代前通过设定年龄阈值来完成的。
 
年老代
年老代内存里包含了长期存活的对象和经过多次Minor GC后依然存活下来的对象。通常会在年老代内存被占满时进行垃圾回收。年老代的垃圾收集叫做Major GC。 Major GC会花费更多的时间。
 
五、 Python 中的内存管理
 
在CPython中,大多数对象的生命周期都是通过对象的引用计数来管理的。引用计数是一种最直观、最简单的垃圾收集计数,与其他主流GC算法比较,它的最大优点是实时性,即任何内存,一旦没有指向它的引用,就会立即被回收。
然而引用计数存在两个比较麻烦的缺陷:
  • 当程序中出现循环引用时,引用计数无法检测出来,被循环引用的内存对象就成了无法回收的内存,引起内存泄露。比如:
list1 = []list1.append(list1)del list1
list1循环引用了自身,第二行执行完后,list1的GC变成了2,执行完del操作后,list1的引用计数变为1,并没有归零,list1的内存空间并没有被释放,造成内存泄露。
  • 维护引用计数需要额外的操作。
在每次内存对象呗引用或者引用被销毁时都需要修改引用计数,这类操作被称为footprint。引用计数的footprint是很高的,使得程序的整体性能受到很大的影响。
  • 为了解决循环引用的问题,CPython特别设计了一个模块——GC module,其主要作用就是检查出循环引用的垃圾对象,并清除他们。该模块的实现,实际上也是引入了前面提到的两种主流的垃圾收集技术——标记清除和分代收集。
  • 为了解决引用计数的性能问题,尽量再内存的分配和释放上获得最高的效率,Python因此还设计了大量的内存池机制

C++代写,C++作业代写,代写C++,编程代写(微信leechanx)