zoukankan      html  css  js  c++  java
  • JVM系列2:垃圾收集器与内存分配策略

      垃圾收集是一个很大话题,本文也只是看了深入理解Java虚拟机总结了下垃圾收集的知识。

      首先按照惯例,先上思维导图:

      GC

      垃圾收集简而言之就是JVM帮我们清理掉内存区域不需要的数据。它主要负责清理堆中实例对象、以及方法区的类对象、常量等。

      GC回收过程

      垃圾回收过程分三步:

      1、将不可达对象进行第一次标记

      2、进行队列执行finalize()方法

      3、进行第二次标记,等待被清除

      第一次标记过程:标记过程第一步是枚举根节点,JVM使用了OOMap记录了根节点位置以便快速定位。然后使用可达性算法寻找可达节点,将不可达节点进行首次标记。

      第一次标记过程需要暂停线程运行(Stop the world),暂停线程的方法有两种,safe point和safe region,safe point将在方法代码中插入访问GC状态的代码,如果为true将自身挂起,但该做法有个问题是GC前wait状态的线程无法访问到他,所以出现了safe region技术,safe region技术使得代码执行只要在某段空间内都可进行垃圾回收,解决了safe point的问题。

      如果是并发垃圾收集器如CML还会分为4步:

      ①、初始标记

      ②、并发标记

      ③、重新标记

      ④、并发回收

      ①、③步骤需要stop the world,②④步骤并发进行,①步骤枚举根节点,②步骤并发进行可达性分析,③步骤修复②步骤因并发引起的可达性节点变更,④步骤进行回收。

      2、执行finalize()方法

      3、使用GC算法进行回收

      垃圾收集首先一个问题是:什么对象需要被收集?有两种典型的实现方法:

      1、引用计数法,当一个对象被引用时,引用数+1,如果一个对象引用数为0,则被清除。该方法实现简单,理解容易,但缺点是无法解决循环引用。因此现在主流JVM采用下个方法。

      2、可达性算法:首先确定根节点root,然后计算其他对象与跟节点是否可达,不可达则被清楚。

      要理解可达性算法需理解以下概念:

      Java的四种引用:

      强引用:引用还在就不会被清除

      弱引用:资源紧张时会被清除

      软引用:下一次GC就被清除

      弱引用:对GC清除没有影响,只是被清除时会获得通知

      哪些可作为根节点?

      可作为“根节点”的对象包括:1、虚拟机栈中本地变量表引用对象

                    2、方法区中类静态属性引用的对象

                    3、方法区中常量引用的对象

                    4、Native方法引用对象

      虚拟机进行GC时用OOmap记录了变化中的根节点,当发生GC时能迅速定位到他们。

      GC回收区域?

      Java一般主力回收区域是堆区域,但也会回收方法区,堆区域主要回收对象实例、方法区回收的是类对象和常量。类对象的回收比较苛刻,需满足  :1、该类实例均被回收 2、加载该类的类加载器被回收 3、类对应Class对象没被引用没被反射。

      在分代算法中堆也被分为了年轻代和老年代,根据不同年代采用不同算法。具体见下文分析。

      计算可达性过程

      GC首先是判断对象是否可达,其中有许多细节,如需用到Stop the world,即需要暂时暂停所有线程运行,Hot Spot虚拟机采用的是主动询问的方式,即虚拟机方法执行过程中会插入访问某内存地址的指令,当虚拟机需要GC时,则将该地址设为不可读,线程感知到虚拟机的信号则将自己挂起。

      该方法有个问题是有些线程已经被挂起不能到达执行询问,因此有了改进方法safe region,即线程代码停留在区域内都可进行GC。如果是一些并发收集器就更复杂了,如CMS收集器它的计算可达性步骤就包括 1、初始标记 2、并发标记 3、重新标记 4、并发回收。13过程是需要stop the world的,3是为了修复步骤2并发标记时,一些引用发生改变的情况。

      当检测到对象不可达时,它会被标记一次,并且进入执行finalized()方法的队列(不保证一定执行),然后被第二次标记,等待被GC。

      GC算法

      1、标记-清除算法

      就是将标记后的对象清理掉,实现简单,效率高,但是会出现磁盘碎片。

      2、标记-整理算法

      在标记-清除的基础上外加了整理步骤,能够将内存空间整理有序,避免产生碎片,但效率更低。

      3、复制算法

      将堆分为两块区域,一次只使用一半,当发生GC时将标记对象清除,存活对象转入另一块区域自动就有序了。效率比标记-整理高,但要牺牲一定空间。

      4、分代收集算法

      就是将Java对象分位不同年代,对不同年代对象采用不同GC算法,例如将区域分为老年代、年轻代,年轻代又分为两块Survivor(10%)和一块Eden(80%)区,一次只使用一块Survivior和Eden区,发生GC清理后将剩余对象转入到另一块Survivor区。

      年轻代进入老年代的方法:1、大对象直接进入老年代

                  2、动态年龄判定,当对象年龄超过所有对象中位数(猜想,也可能是平均数等),进入老年代。

                  3、空间担保,当将剩余对象分配到另一块Survivor区域空间不够时,会进入老年代。

      年轻代主要复制算法,老年代主要采用标记-XX算法。

      垃圾收集器

     

      

      对于垃圾收集器仅仅对他们特性做了了解,如上图有7款垃圾收集器,G1是最新成果,全能的垃圾收集器,其他6个分别只适用于年轻代或老年代,他们的特性如下:

      

  • 相关阅读:
    [转]script之defer&async
    css3渐变gradient
    [转]提高 web 应用性能之 CSS 性能调优
    [转]深入了解 CSS3 新特性
    进程中t.start(), t.daemon() t.jion()的使用
    创建进程
    进程与进程之间通信Manager
    简版线程池
    Python上下文管理
    绝版线程池
  • 原文地址:https://www.cnblogs.com/llsblog/p/10627533.html
Copyright © 2011-2022 走看看