zoukankan      html  css  js  c++  java
  • GC垃圾回收总结

    对于C++用户来说,用Java最大的感受就是不用操心内存了,但完全自动的回收机制反而让我感觉不安,万一回收失败了,我要调试的就不仅仅是我的代码了,还有虚拟机呀。于是看了Java虚拟机的书和相关的资料,总结一下相关的知识。

    对象还在吗?

    1)引用计数算法

    基本思路是为每个对象加一个计数器,记录指向这个对象的引用数量。每次有一个新的引用指向这个对象,计数器加一;反之每次有一个指向这个对象引用被置空或者指向其他对象,计数器减一。任何时刻计数器为 0 的对象都是不可能再被使用,是可以删除的。

    引用计数的优点是 1)实现简单,不需要太多运行时(run-time)的支持,可以在原生不支持 GC 的语言里实现。2)对象会在成为垃圾的瞬间被释放,不会给正常程序的执行带来额外中断。比如:微软的COM技术,使用ActionScript3的FlashPlayer等。它的问题是很难解决对象之间相互循环引用的问题。另外,引用计数对正常程序的执行性能有影响(每次引用赋值都要改计数器),特别是在多线程环境下(改计数器要加锁同步)。

    2)可达性分析算法

    基本思路是通过一系列称为“GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。主流的商用程序语言Java,C#等都有这种实现。Java中作为GC Roots的对象有:1)虚拟机栈中引用的对象;2)方法区中类静态属性引用的对象;3)方法区中常量引用的对象;4)本地方法中JNI(Native方法)引用的对象。

    垃圾回收算法

    1)标记-清除算法

    这种算法就像它的名称一样,先标记再清除。首先标记出所有需要回收的对象,在标记完成之后统一回收所有被标记的对象。主要有两个不足的地方:1)效率问题,标记和清除的过程效率不高;2)空间问题,标记清除之后产生大量不连续的内存碎片,导致程序在运行中需要分配较大的对象时,无法找到足够的连续内存而触发另一次垃圾收集动作。

    2)节点复制算法

    基本思路是把整个内存空间一分为二,每次只使用其中的一块。当一块内存用完了,就把还存活的对象复制到另一块,然后把已使用的内存清理掉。主要缺点是1)总有一半空间空闲着无法利用,2)是它使用内存的方式与现有的内存换页、Cache 换入换出机制有潜在的冲突。但它有个很大的优点: 所有的对象在内存中永远都是紧密排列的,所以分配内存的任务变得极为简单,只要移动一个指针即可。对于内存分配频繁的环境来说,性能优势相当大。另外,由于不需要清扫整个内存空间,所以如果内存中存活对象很少而垃圾对象很多的话,触发 GC 造成的中断会小于标记-清扫。现在的商业虚拟机都采用这种方法回收新生代。

    优化:把内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和一块Survivor空间。当回收时把Eden和Survivor中还存活的对象复制到另一块Survivor中,然后清理Eden和过时的Survivor空间,HotSpot默认Eden:Survivor = 8:1,也就是只有10%的空间被浪费。

    3)标记-整理算法

    针对老年代对象存活率较高使用的算法,首先标记需要回收的对象,然后让所有存活的对象向一端移动,然后直接清理掉边界以外的内存。

    4)分代回收算法

    基本思路是这样的:程序中存在大量的临时对象,分配出来之后很快就会被释放,而同时如果一个对象分配出来之后相当长的一段时间内都没回收,那么极有可能它的生命周期很长,尝试收集它会是无用功。所以可以把内存有意识地按“对象年龄”分成若干块,所有对象的分配都在青代进行,青代塞满只对青代做 GC,然后把存活下来的对象移动到中代,直到中青代都塞满,再把存活下来下来的对象移动到老代

    当然这些回收算法并不是单独使用的,而是几种组合进行,以达到效率最大化。

  • 相关阅读:
    批量ping工具fping
    图形文件元数据管理工具exiv2
    JPG图片EXIF信息提取工具exif
    网络图片嗅探工具driftnet
    复杂密码生成工具apg
    前端面试题目准备
    JS中同步与异步的理解
    angular初体验
    媒体查询的两种方式
    CSS3多列布局
  • 原文地址:https://www.cnblogs.com/benjaming/p/8432297.html
Copyright © 2011-2022 走看看