2019独角兽企业重金招聘Python工程师标准>>>

垃圾回收(Garbage Collection, GC)主要需要考虑的问题:

  • 哪些内存需要回收?
  • 什么时候回收?
  • 如何回收?

哪些内存需要回收

虚拟机栈、本地方法栈、程序计数器由于是线程独有,且栈帧的内存大小在类结构确定时已经相对确定所以不需要考虑回收问题,方法结束或线程结束自然回收。需要回收的是Java堆以及方法区

什么时候回收以及如何回收

在一个对象不可能再被任何途径使用时回收;

微软的COM(Component Object Model)技术、使用ActionScript3的FlashPlayer、Python语言和Squirrel使用了引用计数算法进行内存管理,而主流商业语言(Java、C#、Lisp等)主流实现算法都是可达性分析算法。

  1. 引用计数算法(Reference Counting):给对象添加一个引用计数器,当有一个地方引用它时,计数器加1,引用失效计数器减1,当计数器为0时,表示此对象不再被引用,可以回收;缺点:无法解决对象相互循环引用问题
  2. 可达性分析算法(Reachability Analysis):通过一系列称为“GC Roots”的对象作为起始点,从这个点开始向下搜索,所走的路径称为引用链(Reference Chain),当一个对象没有任何引用链也GC Roots相连时,将对对象进行第一次标记并通过该对象的分析(1.是否重写了finalize()方法,2.finalize()方法有没有被虚拟机调用过),如果重写了方法且没有被调用过将会被放置到一个叫做F-Queue的队列中,稍后将被逐个执行finalize()方法,之后虚拟机将对这些对象进行二次标记,如果在执行了finalize()方法后,可达性分析可以通过将被移出“待回收”集合继续存活。

回收方法区

回收运行时常量池,与Java堆对象回收类似

回收无用类,满足一下3个条件才算是“无用类”:

  1. 该类的所有实例已被回收,即在Java堆中不再存在该类实例
  2. 加载该类的ClassLoader已经被回收
  3. 该类对应的java.lang.Class对象没有任何地方被引用,无任何地方通过反射访问该类的方法

可以使用-Xnoclassgc关闭这部分的回收,还可以使用-verbose:class以及-XX:+TraceClassLoading、-XX:+TraceClassUnLoading查看类加载和卸载信息。

垃圾回收算法

  1. 标记-清除算法:

    1. 基本算法:判断每个对象是否应该回收,需要回收的标记,最后一起清除;缺点:会出现很多不连续空内存,标记和清除小女都不高
    2. 衍生:复制算法:用一半内存空着,标记完后,将没标记的复制到空内存,清除之前所有;缺点:只有一半内存可以使用
    3. 优化复制算法:将内存分为了80%的Eden以及两块10%的Survivor,每次使用90%内存,10%用于留空复制,不够像老年代借
  2. 标记-整理算法
    1. 基本算法:标记和上同,将存活的对象移动到前面,清除后面的内存
  3. 分代算法:根据对象存活周期的不同将内存分为几块,一般把Java堆分为新生代和老年代,新生代中每次有大量的对象死亡,所以使用优化的复制算法;而老年代存活率高,所以使用“标记-清除”或者“标记-整理”算法

垃圾回收器

Java虚拟机规范中堆垃圾收集器应该如何实现并没有明确的规定,针对JDK1.7的Hotspot虚拟机,实现了其中不同的垃圾回收器:

图片来源(https://blogs.oracle.com/jonthecollector/entry/our_collectors),上图中的连线两端的垃圾回收器可以配合使用

  1. Serial收集器:单线程的垃圾收集器,当使用它收集垃圾时,必须停止其他所有线程,曾经是JDK1.3.1之前的唯一新生代垃圾会回收器,client版本JVM的默认选择
  2. ParNew(new parallel)收集器:Serial的多线程版本,与Serial公用了大量相同的算法,Server版本JVM新生代的首选,参数: -XX:+UserParNewGC
  3. CMS(Concurrent Mark Sweep)收集器:第一个实现了让垃圾回收线程与用户回收线程(基本上)同时工作的收集器,一般用于老年代收集,参数: -XX:+UseConcMarkSweepGC
  4. Parallel Scavenge收集器:新生代多线程收集器,使用复制算法,他与上面收集器的注重点不同,上面收集器注重点是在尽量减少垃圾收集时用户线程的停顿时间,而次收集器注重达到一个可控的吞吐量(throughput)。通过两个参数精确控制吞吐量:-XX:MaxGCPauseMillis设置最大停顿时间、-XX:GCTimeRatio直接设置吞吐量大小。还有一个开关参数参数-XX:+UserAdaptiveSizePolicy,打开后可以不用手动设置新生代大小(-Xmn)、Eden与Survivor区比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)
  5. Serial Old:是Serial的老年代版本,使用“标记-整理”算法
  6. Parallel Old:是Parallel Scavenge的老年代版本,使用“标记-整理”算法

*吞吐量(Throughput) = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)

CMS(Concurrent Mark Sweep)收集器是以获得最短回收停顿时间为目的的收集器,从名字可以看出CMS是基于“标记-清除”算法实现的,主要分为四个步骤:

  1. 初始标记(CMS Initial mark)
  2. 并发标记(CMS Concurrent mark)
  3. 重新标记(CMS remark)
  4. 并发清除(CMS Concurrent sweep)

其中初始标记会停止所有用户进程,标记出所有与GC Roots直接相连的对象,这个过程耗时极短;之后并发标记时,标记线程将和用户线程并发执行,这个过程耗时最长,但由于和用户线程并发执行所以这段时间并不会造成停顿;重新标记将对并发标记阶段用户进程造成的对象引用变更进行再次标记,这个阶段也会停止所有用户线程;并发清除阶段,清除进程将和用户进程并发进行;

优点:极低的停顿时间,在注重交互的系统中,体验极佳

缺点:

  1. 在并发阶段,收集器线程将一直独占一部分CPU资源,默认是(CPU数量+3)/4的CPU核数,当CPU核数<=4时,占用资源过多,将造成用户进程执行速度降低;
  2. 在并发清除期间参数的浮动垃圾(Floating Garbage)无法处理,只能下次GC处理,所以CMS收集器的激活频率会高于其他,默认当老年代使用了68%空间激活,而其他同代收集器几乎完全填满才进行收集,可以通过参数-XX:CMSInitiatingOccupancyFraction设置激活所需要的内存占用百分比;
  3. 由于CMS使用“标记-清除”算法,将产生大量内存碎片,可能造成老年代内存剩余足够,但找不到合适大小的内存空间,不得不提前进行一次Full GC。为了解决这个问题CMS收集器提供了-XX:+UseCMSCompactAtFullCollection,当出现上述情况时,进行内存碎片合并,还有另一个参数-XX:CMSFullGCsBeforeCompaction,默认为0,即每次进入Full GC时都进行内存碎片整理

G1(Garbage first)收集器:

Sun赋予它的使命是未来可以替代CMS,

G1优势:

  • 并行与并发
  • 分代收集
  • 空间整合
  • 可预测的停顿

G1的运作大致可分为下面的几个步骤:

  • 初始标记(Initial Marking)
  • 并发标记(Concurrent Marking)
  • 最终标记(Final Marking)
  • 筛选回收(Live Data Counting and Evacuation)

对象分配空间的规则:

大多数时候,新对象分配在Eden区,当Eden区内存不足时,系统将发起一次Minor GC,但也有特殊情况:

  • 需要大量连续空间的Java对象,如长字符串,数组,需要内存超过-XX:PretenureSizeThreshold参数设置值,将直接在老年代分配

当对象在Eden出生每经过一次Minor GC并存活下来,年龄计数加1,当年龄大于-XX:MaxTensuringThreshold设置值,将进入老年代,也有特殊情况:

  • 当出现Survivor区中相同年龄对象总大小大于Survivor区一半,年龄大于等于该年龄的对象都进老年代

在每次Minor GC 开始之前,虚拟机将进行以下流程:

*是否允许失败,有参数-XX:+HandlePromotionFailure设置

转载于:https://my.oschina.net/u/1413049/blog/684017

Java虚拟机学习(四)相关推荐

  1. Java虚拟机学习(3): 类加载机制

    类加载机制 JVM把class文件加载的内存,并对数据进行校验.转换解析和初始化,最终形成JVM可以直接使用的Java类型的过程就是加载机制. 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的生命 ...

  2. Java虚拟机学习(8):查看JVM参数及值的命令行工具

    查看JVM各个参数值方式 1. HotSpot vm中的各个globals.hpp文件  查看jvm初始的默认值及参数 globals.hpp globals_extension.hpp c1_glo ...

  3. Java虚拟机学习(7):对象内存分配与回收

    对象优先在Eden上分配 大多数情况下,对象优先在新生代Eden区域中分配.当Eden内存区域没有足够的空间进行分配时,虚拟机将触发一次 Minor GC(新生代GC).Minor GC期间虚拟机将E ...

  4. Java虚拟机学习(6):对象访问

    对象访问会涉及到Java栈.Java堆.方法区这三个内存区域. 如下面这句代码: 1 Object objectRef = new Object(); 假设这句代码出现在方法体中,"Obje ...

  5. Java虚拟机学习(5):内存调优

    JVM调优主要是针对内存管理方面的调优,包括控制各个代的大小,GC策略.由于GC开始垃圾回收时会挂起应用线程,严重影响了性能,调优的目是为了尽量降低GC所导致的应用线程暂停时间. 减少Full GC次 ...

  6. Java虚拟机学习(4):JDK可视化监控工具

    1.JConsole JConsole工具在JDK/bin目录下,启动JConsole后,将自动搜索本机运行的jvm进程,不需要jps命令来查询指定.双击其中一个jvm进程即可开始监控,也可使用&qu ...

  7. Java虚拟机学习(2):垃圾收集算法

    跟踪收集器 跟踪收集器采用的为集中式的管理方式,全局记录对象之间的引用状态,执行时从一些列GC  Roots的对象做为起点,从这些节点向下开始进行搜索所有的引用链,当一个对象到GC  Roots 没有 ...

  8. Java虚拟机学习(1):体系结构 内存模型

    一:Java技术体系模块图 二:JVM内存区域模型 1.方法区 也称"永久代" ."非堆",  它用于存储虚拟机加载的类信息.常量.静态变量.是各个线程共享的内 ...

  9. 深入java虚拟机学习 -- 类的加载机制(续)

    昨晚写 深入java虚拟机学习 -- 类的加载机制 都到1点半了,由于第二天还要工作,没有将上篇文章中的demo讲解写出来,今天抽时间补上昨晚的例子讲解. 这里我先把昨天的两份代码贴过来,重新看下: ...

  10. java虚拟机学习-JVM调优总结-新一代的垃圾回收算法(11)

    java虚拟机学习-深入理解JVM(1) java虚拟机学习-慢慢琢磨JVM(2) java虚拟机学习-慢慢琢磨JVM(2-1)ClassLoader的工作机制 java虚拟机学习-JVM内存管理:深 ...

最新文章

  1. 从零开始搭建基于CEFGlue的CB/S的winform项目
  2. PAT1066 Root of AVL Tree (25)(AVL树)
  3. go python php_php 、go 、python http请求(get和post)
  4. 【转】用户显示数据库表通用程序
  5. java 8 lambda 排序_Java8 用Lambda表达式给List集合排序的实现
  6. 用python偷偷给班级群女同学的颜值进行排名,排最后的 说开学要打爆我
  7. 博客迁移到github
  8. 项目讨论:本地手机经销商怎样用移动站点开展本地营销?
  9. python内置方法总结
  10. oracle创建表空间并赋予权限
  11. WebRTC NAT穿透服务器 coturn服务搭建
  12. 我国第一个“法律语言语料库”
  13. 【Android 常见控件使用】Button(按钮)与ImageButton(图像按钮)
  14. php中文分词nlp,几种常见的PHP中文分词系统
  15. 获取照片经纬度(wgs84)转高德经纬度(gcj02)
  16. APP在推广之渠道为王(二 )
  17. 应届生offer指南
  18. c语言以16进制输出大写字母,C语言二进制、八进制、十六进制整数书写和输出...
  19. Outlook2007备份邮件规则、联系人以及账号及在Outlook 2007中删除自动记忆的收件人...
  20. 关于Jmeter中的函数和变量用法

热门文章

  1. Python如何安装模块
  2. /proc/meminfo 文件
  3. php超链接怎么写,怎么给一个PHP密码访问页面加超链接
  4. Systrace分析app启动分析
  5. Linux中的Page cache和Buffer cache详解
  6. 蓝桥杯省赛2017年Java组B组
  7. yum install php-pecl-mongo,pecl安装php mongodb扩展
  8. inster into java_SELECT INTO 和 INSERT INTO SELECT 两种表复制语句
  9. mysql正则表达式教学视频教程_MySQL正则表达式入门教程
  10. python实验九答案_Python程序设计实验报告:实验九 python 包管理