(转)Java垃圾回收基本过程
本编博客内容来自oschina,是一篇译文,文中图片比较直观的介绍了JVM进行垃圾回收的过程。原文内容来自oracle官网:Java Garbage Collection Basics
oschina原译文地址:https://www.oschina.net/translate/java-gc
一、什么是自动垃圾回收?
自动垃圾回收时一种在堆内存中找出哪些对象在被使用,还有哪些对象没被使用,并且将后者删掉的机制。所谓使用中的对象(已引用对象),指的是程序汇总有指针指向的对象;而未使用中的对象(未引用对象),则没有被任何指针给指向,因此占用的内存也可以被回收掉。
在用C之类的编程语言时,程序员需要自动手动分配和释放内存。而Java不一样,它有垃圾回收器,释放内存由回收器负责。本文接下来将介绍垃圾回收机制的基本过程。
第一步:标记
垃圾回收的第一步是标记。垃圾回收器此时会找出哪些内存在使用,还有哪些不是。
上图中,蓝色表示已引用对象,橙色表示未引用对象。垃圾回收器要检查完所有的对象,才能知道哪些有被引用,哪些没。如果系统里所有的对象都要检查,那这一步可能会相当耗时间。
第二步:清除
这一步会删掉标记处的未引用对象。
内存分配器会保留指向可用内存的引用,以供分配新对象。
压缩
为了提升性能,删除了未引用对象后,还可以将剩下的已引用对象放在一起(压缩),这样就能更简单快捷地分配新对象了。
为什么需要分代垃圾收集
之前说过,逐一标记和压缩Java虚拟机里的所有对象非常低效:分配的对象越多,垃圾回收需要的时间就越久。不过,根据统计,大部分的对象,其实用没多久就不用了。
来看个例子吧。(下图中,竖轴代表已分配的字节,而横轴代表程序运行时间)
上图可见,存活(没被释放)的对象随运行时间越来越少。而图中左侧的那些峰值,也表明了大部分对象的寿命都很短
JVM 分代
根据之前的规律,就可以用来提升JVM的效率了。方法是,把堆分成几个部分(就是所谓的分代),分别是新生代、老年代、永久代。
新对象会被分配在新生代内存中。一旦新生代内存满了,就会开始触发小型垃圾回收,对死掉的对象进行清理。新生代内存,死掉的越多,回收过程就越快;至于那些还存活的对象,此时就会增加年龄老化,并最终进入到老年代内存。
Stop the World事件——所有的小型垃圾回收都属于一种叫“Stop the World”的事件。在这种事件发生时,所有的程序线程都要暂停,直到事件完成(比如这里就是完成了所有回收工作)为止。
老年代用来保存长时间存活的对象。通常,设置一个阈值,当达到该年龄时,年轻代对象会被移动到老年代。最终老年代也会被回收。这个实践称为Major GC。
Major GC也会触发STW(Stop the World)。通常,Major GC会慢很多,因为它涉及到所有存活对象。所以,对于响应性的应用程序,应该尽量避免Major GC。还要注意,Major GC的STW的时长受老年代垃圾回收器类型的影响。
永久代包含JVM用于描述应用程序中类和方法的元数据。永久代是由JVM在运行时根据应用程序使用的类来填充的。此外,Java SE类库和方法也存储在这里。
如果JVM发现某些类不再需要,并且其他类可能需要空间,则这些类可能会被回收。
二、世代垃圾收集过程
现在你已经了解了为什么堆被分为不同的代,现在是时候看看这些空间时如何相互作用的。后面的图片将介绍JVM中的对象分配和老化过程。
1、首先,将任何新对象分配给eden空间。两个survivor空间都是空的。
2、当eden空间填满时,会触发轻微的垃圾收集。
3、引用的对象被移动到第一个survivor空间。清除eden空间时,将删除为引用的对象。
4、在下一次Minor GC中,Eden区也会做同样的操作。删除未被引用的对象,并将被引用的对象移动到Survivor区。然而,这里,他们被移动到了第二个Survivor区(S1)。此外,第一个Survivor区(S0)中,在上一次Minor GC幸存的对象,会增加年龄,并被移动到S1中。待所有幸存对象都被移动到S1后,S0和Eden区都会被清空。注意,Survivor区中有了不同年龄的对象。
5、在下一次Minor GC中,会重复同样的操作。不过,这一次Survivor区会交换。被引用的对象移动到S0.幸存的对象增加年龄。Eden区和S1被清空。
6、此幻灯片演示了promotion。在较小的GC之后,当老化的物体达到一定的年龄阈值(在该示例中为8)时,它们从年轻一代晋升到老一代。
7、随着较小的GC持续发生,物体将继续被推广到老一代空间。
8、所以这几乎涵盖了年轻一代的整个过程。最终,将主要对老一代进行GC,清理并最终压缩该空间。
最新文章
- ASP.NET用QQ,网易发送邮件以及添加附件
- Office 365 系列五 -------- Imap邮箱迁移步骤
- 分离EF connectionString里的db连接串
- iOS9和Xcode7
- 【JS】Beginner3 &; 4 &; 5 &; 6:Maths &; Logic &; Conditonal &; Looping
- PHP制作pdf文档方法
- executeBatch()相关操作汇总
- 【java】io流之字节流转为字符流:java.io.OutputStreamWriter和java.io.InputStreamReader
- ISE14.7安装教程(转)
- 重写equals()和hashCode()
- HTML(五)HTML表格
- 性能测试监控工具nmon安装及使用方法
- Windows 10 IoT Serials 10 – 如何使用OCR引擎进行文字识别
- 日期控件——my97
- sqlplus的非交互式使用
- vba文件对比并高亮显示
- python获取文件扩展名的方法
- [BZOJ2683]简单题/[BZOJ1176][BalkanOI2007]Mokia
- Linux---关闭Elasticsearch进程,并重新启动
- IIS配置导入导出
热门文章
- PCL点云库(Point Cloud Library)简介
- wpf相关好资源
- js 中 new call apply bind JSON.stringify 的原理以及模拟实现
- 小D课堂 - 新版本微服务springcloud+Docker教程_4-05 微服务调用方式之feign 实战 订单调用商品服务
- Android 单元测试学习计划
- 在java开发环境中,快捷键的使用及用法
- sql如何判断表字段是否存在默认值
- cocos2dx-android-添加64位编译
- kubeadm安装集群系列-1.基础服务安装
- PHP学习(3)——数据的存储与检索