贴吧网站怎么做,辽宁建设工程信息网查,华资源网站建设,织梦网站图片怎么修改不了所谓垃圾回收#xff0c;也就是要回收已经“死了”的对象。
那我们如何判断哪些对象“存活”#xff0c;哪些已经“死去”呢#xff1f;
一、判断对象已死
1、引用计数算法
给对象中添加一个引用计数器#xff0c;每当有一个地方引用它时#xff0c;计数器就加一…所谓垃圾回收也就是要回收已经“死了”的对象。
那我们如何判断哪些对象“存活”哪些已经“死去”呢
一、判断对象已死
1、引用计数算法
给对象中添加一个引用计数器每当有一个地方引用它时计数器就加一当引用失效时计数器就减1任何时刻计数器为0的对象就是不可能再被使用的。
但是在Java虚拟机里面没有选用引用计数算法来管理内存。
优点实现简单效率高。
缺点很难解决对象之间相互循环引用的问题。
2、可达性分析算法
通过一系列的称为“GC Roots”的对象作为起始点从这些节点开始向下搜索搜索走过的路径称为引用链(Reference Chain)当一个对象到GC Roots没有任何引用链相连用图论的话来说就是从GC Roots到这个对象不可达时则证明此对象是不可用的。
如图object5、object6、object7 为可回收对象 主流的Java虚拟机使用可达性分析算法
关于GC Roots 在Java语言中GC Roots包括以下几种 虚拟机栈栈帧中的本地变量表中引用的对象方法区中类静态属性引用的对象方法区中常量引用的对象本地方法栈中Native方法引用的对象 无论是通过引用计数算法判断对象的引用数量还是通过可达性分析算法判断对象是否引用链可 达判定对象是否存活都和“引用”离不开关系。
引用分为四种
强引用代码中普遍存在垃圾收集器不会回收强引用的对象。比如new Object软引用有用但非必需在系统将要发生内存溢出异常OOM之前会把这些对象列入回收范围进行回收。弱引用非必需无论当前内存是否足够下次垃圾回收都会回收掉这些对象。虚引用最弱的引用关系是否有虚引用不对其生存时间构成影响。相当于什么时候回收都没问题也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知
二、三种垃圾回收算法
1、标记-清除算法
最基础的收集算法——“标记-清除”Mark-Sweep算法。一般用于老年代
算法分为“标记”和“清除”两个阶段
标记出需要回收的对象清除被标记的对象
缺点
当有大量对象等待被回收此时就需要大量的标记和清除操作导致两个过程的效率随对象数量增长而降低执行效率不稳定标记清除后会产生大量不连续的内存碎片导致空间碎片化问题 2、标记-复制算法
为了解决效率问题标记-复制算法出现了。他将内存分为两块每次只使用其中一块当一块内存用完了就将还存活的对象复制到另一块上面然后把已经使用过的内存空间一次性清理掉。
缺点内存缩小为原来的一半。 但是在新生代的内存划分中研究表明有98%的对象熬不过第一轮收集因此没必要采用11的内存划分。针对这种情况产生了半区分代策略。是把新生代分为一块较大的Eden空间和两块较小的 Survivor空间每次分配内存只使用Eden和其中一块Survivor。发生垃圾搜集时将Eden和Survivor中仍 然存活的对象一次性复制到另外一块Survivor空间上然后直接清理掉Eden和已用过的那块Survivor空 间。HotSpot虚拟机默认Eden和Survivor的大小比例是8∶1 。如果另外一块 Survivor空间没有足够空间存放上一次新生代收集下来的存活对象这些对象便将通过分配担保机制直 接进入老年代这对虚拟机来说就是安全的。
3、标记-整理算法
在Mark-Sweep算法的基础上做了改良用于解决空间碎片化问题。标记-整理(Mark-Compact)算法在标记后不是简单做清除而是让所有存活的对象都向一端移动然后清理掉端边界以外的内存。一般用于老年代。
优点解决了空间碎片化问题为后续内存分配和访问提高效率
缺点使内存回收的过程更加复杂。如果移动存活对象尤其是在老年代这种每次回收都有大量对象存活区域移动存活对象并更新所有引用这些对象的地方必须全程暂停用户应用程序才能进行。 三、安全点和安全区域
安全点
在做可达性分析时需要保持分析期间整个系统不会发生变化这就导致GC进行时必须停顿所有Java执行线程(Stop The World)即使是在号称几乎不会发生停顿的CMS收集器中枚举根节点时也必须要停顿。
程序执行时并非在所有地方都能停下来开始GC只有在到达安全点(Safepoint)时才能暂停。Safepoint 的选定既不能太少以致于让GC等待时间太长也不能过于频繁以致于过分增大运行时的负荷。所以安全点的选定基本上是以程序“是否具有让程序长时间执行的特征”为标准进行选定的例如方法调用循环跳转异常跳转等。
如何在GC发生时让线程都跑到最近的安全点再停顿下来
抢先试中断先把所有线程中断发现不在安全点的线程恢复线程让它跑到安全点。主动式中断设置一个不可读的内存位置作为中断标志标志与安全点重合当线程执行到这个标志时自己中断挂起。
安全区域
安全区域(Safe Region)是指在一段代码片段中引用关系不会发生变化。在这个区域的任何地方开始GC都是安全的。典型的安全区域比如线程处于Sleep状态或者Blocked状态。
在线程执行到Safe Region中的代码时首先标识自己已经进入了Safe Region。当要发起GC时就不用管标识为Safe Region状态的线程了。当线程要离开Safe Region时要检查是否处于GC状态如果是就要继续等待直到收到可以安全离开Safe Region的信号为止。