jvm--Garbage Collection

垃圾回收(GC)一直是java语言的重中之重。

1 对象状态鉴别

  1.1 标记对象是否可回收一般有两种算法:

  • 引用计数算法:给每个对象添加一个引用计数器,当引用一次时+1,当引用时效时-1,当计数器为0时即可回收。该算法最大的缺点是当多个对象相互循环引用时将用不释放。
  • 可达性分析算法:将“GC Roots”作为起点向下搜索,搜索所走过的路径称为引用链,当对象与GC roots没有任何连接时即可释放。GC Roots包含如下四种对象:虚拟机栈(战阵中的本地变量表)中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象、本地方法栈中JNI(Native方法)引用的对象。

  1.2 引用

  在JDK1.2以前,java中应用的定义很狭义:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用;在JDK1.2之后,java对引用的概念进行了扩充分为如下四类:

  • 强引用:代码中普遍存在的,如“Object obj = new Object()”这类,只要强引用存在,垃圾回收器永远不会回收被引用的对象。
  • 软引用:用来描述一些还有用但并非必须的对象,在系统发生内存溢出之前,将这些对象列入可回收队列进行第二次回收。
  • 弱引用:用来描述非必需的对象,强度比软引用稍弱,无论当前内存是否充足,弱引用关联的对象只能生存到下一次垃圾回收之前。
  • 虚引用:最弱的一种引用关系,完全不会对关联对象的生存时间产生影响,也无法通过虚引用获取一个对象的实例,完全是为了在这个对象被回收时收到一个系统通知。

  1.3 两次确认(不推荐使用finalize()方法)

  在可达性分析中不可达的对象也不是一定被回收,一个对象被宣判死刑,至少要经历两次标记过程:如果对象在进行可达性分析时发现没有与GC Roots相连,它将会被将第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法或者finalize()方法已经被虚拟机调用过,将视为“没必要执行”,立即回收。

  当这个对象被判定有必要执行finalize()方法时,这个对象将会放置在F-Queue队列中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程触发对象的finalize()方法,但不承诺保证方法运行结束。finalize()方法是对象逃脱死亡的最后一次机会,稍后GC将对F-Queuezhongde对象进行第二次小规模标记,只要重新与GC Roots引用链上的任何一个对象建立关联即可完成救赎,否则将被回收。

  值得注意的是,任何一个对象的finalize()方法只会被系统自动调用一次,此外finalize()方法并不推荐使用,而是应该更多的使用try-finally等其他方式。

  1.4 方法区回收

  大多数人可能认为方法区(HotSpot虚拟机中的永久代)是没有垃圾收集的,其不然。永久代的垃圾回收只要收集“废弃常量”和“无用的类”两部分。

  • 废弃常量:与回收堆中的对象相似,以常量池中字面量的回收为例,如果一个字符串“abc”已经进入了常量池中,但当前没有任何一个String对象引用了“abc”常量,如果发生内存回收,而且必要时将会将“abc”这个常量清除出常量池。常量池中的其他类、接口、方法的符号引用也与此类似。 无用的类:无用的类判断条件相对苛刻很多,只有同时满足如下三个条件才可算为无用的类。
    • 该类的所有实例都已经被回收,即java堆中不存在该类的任何实例
    • 加载该类的classLoader已经被回收
    • 该类对应的java.lang.Class对象没有任何地方被应用,无法在任何地方通过反射方位该类的方法

2 垃圾收集算法

  • 标记-清除算法   首先标记需要回收的对象,然后在标记完成后统一回收所有被标记的对象。具有两个缺点,其一,效率问题,标记和清楚两个阶段效率都不高;其二,空间问题,标记清除之后会产生大量不连续的碎片。(白色区域为未使用,绿色区域为存活对象,红色区域为可回收)

 

  • 复制算法  为了解决效率问题进化而来。将可用内存划分为大小相等的两块,每次使用其中的一块,当这一块内存用完就将还存活的对象复制到另一块内存上,然后将已使用的内存一次性清空,这样不必考虑内存碎片问题。现在的商业虚拟机都采用这种收集方法回收新生代内存,俱IBM公司调研新生代中的对象98%是“朝生夕死”的,所以并不需要1:1划分,而是将内存划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和一块Survivor。当回收时,Eden和Survivor中还存活的对象一次性复制到另一块Survivor中,并其清理掉Eden和刚才使用的Survivor。在HotSpot中,Eden和Survivor的比例大小是8:1。
  • 标记-整理算法  同样首先标记需要回收的对象,但后续步骤是让存活的对象都向一端移动,然后直接清理掉边界外的内存。(白色区域为未使用,绿色区域为存活对象,红色区域为可回收)
  • 分代收集算法  根据对象存活周期的不同将内存划分为几块,一般分为新生代和老年代,根据各个年代的特点采用适当的手机算法。新生代采用复制算法,老年代采用“标记-清理”或者“标记-整理”算法。

3 内存分配与回收策略

  java技术体系中所提倡的自动内存管理最终可归结为自动化地解决了两个问题:给对象分配内存以及回收分配给对象的内存。对象的内存分配往大方向讲就是在堆上分配,主要是在新生代的Eden区,如果启动了本地线程分配缓冲,将按线程优先在TLBA上分配。内存分配具有几条普遍的分配规则:

  • 对象优先在Eden分配,当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC 
  • 大对象直接进入老年代,大对象就是需要大量连续空间的java对象,最典型的是长字符串或数组
  • 长存活期的对象将进入老年代,对象经过一次Minor GC存活并被Survivor容纳,该对象年龄置为1,以后没熬过一次Minor GC,年龄就加1,当到一定程度就会晋升到老年代
  • 动态对象年龄判定,虚拟机并不是永远要求只有到年龄才能晋升老年代,如果相同年龄所有对象的大小总和大于Survivor空间一半,则其他大于该年龄的对象可以直接进入老年代
  • 空间分配担保,在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对总空间,如果条件成立,Minor GC可以确保安全,否则就可能需要一次Full GC

  Minor GC 和 Full GC 区别

  • 新生代GC(Minor GC):发生在新生代的垃圾收集动作,相对较频繁,回收速度也较快
  • 老年代GC(Major GC / Full GC):发生在老年代的GC,出现了Major GC,经常会伴有至少一次Minor GC,Major GC速度一般比Minor GC慢10倍以上

4 HotSpot的GC算法实现

  • 枚举根节点  可达性分析对于执行时间的敏感体现在GC停顿上,因为这项分析工作必须在一个能确保一致性的快照中进行(这里的一致性是指整个分析过程中整个执行系统看起来就像被冻结在某个时间点上,不可以出现分析过程中对象引用关系还在不断变化的情况,以保证分析结果准确性),这点也是GC进行时必须停顿所有java执行线程(stop the world)的一个重要原因。在Hotspot虚拟机中,为了提升可达性分析效率,当执行系统停顿下来后,通过一组称为OopMap的数据结构来直接得知那些地方存放着对象引用,以便快速统计对象状态。
  • 安全点  在OopMap的帮助下,HotSpot可以准确快速的完成GC Roots枚举。HotSpot没有为每条机器指令都生成OopMap,而是在某些特定的位置记录这些信息,即为安全点;也只有到达安全点才能停顿。如何在发生GC时所有线程都跑到最近的安全点停顿下来,有两种方案可选:其一,抢断式中断(基本被抛弃),首先把所有线程中断,如果发现有线程中断的地方不在安全点,就让线程恢复并跑到安全点;主动式中断,当GC需要中断时,不直接对线程操作,而是设置与安全点位置重合的一个标识,每个线程执行时主动去轮训这个标识,当发现标识为true时将自己中断挂起。
  • 安全区域  安全点可以保证程序执行时在不长的时间内就会进入安全点,但是对于处于sleep或blocked等状态的没有分配CPU时间的线程无法进入安全点,这时候需要安全区域来解决。安全区域指一段代码片段中,引用关系不会发生变化,这个地方区域中的任意地方开始GC都是安全的。当线程执行到安全区域的代码中时,将标识自己进入安全区域,这样JVM发起GC时就就不用管处在安全区域的进程了。

5 收集器简介

 

转载于:https://www.cnblogs.com/climber1990/p/7689621.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/571788.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux安装mongo卸载mongo,CentOS7安装及卸载MongoDB.md

安装 MongoDB 社区版本配置 yum 包管理系统创建 /etc/yum.repos.d/mongodb-org-4.2.repo 文件,这样你就可以使用 yum 安装 MongoDB,文件内容如下:123456[mongodb-org-4.2]nameMongoDB Repositorybaseurlhttps://repo.mongodb.org/yum/redhat/…

程序固化到优盘中_将Windows 8/10 系统装进优盘

介绍Windows To Go技术Windows 有一项相当吸引人的神奇功能——“Windows To Go”,它可以让你将 Windows 完整安装到U盘、移动硬盘等便携设备上,并且能随处在不同的电脑硬件上直接运行,让系统可以随身携带!简单说来,这…

如何获得物体的主要方向?

问题来源为网友提供的资料,原文地址为:《Object Orientation, Principal Component Analysis & OpenCV》 问题描述:对于这样的图像(2副,采用了背投光),如何获得上面工件的主要方向主要思路&…

Linux的开源免费办公软件,开源免费Office办公套件(LibreOffice)

LibreOffice是一款全面的开源免费Office办公套件,软件拥有强大的数据导入和导出功能,能直接导入 PDF 文档、微软 Works、LotusWord,支持主要的 OpenXML 格式。软件本身并不局限于 Debian 和Ubuntu 平台,支持 Windows、Mac、PRM pa…

ubuntu安装ftp_如何在 Ubuntu 20.04 上安装 Webmin

本文最先发布在: 如何在 Ubuntu 20.04 上安装 Webmin​www.itcoder.techWebmin 是一个开源控制面板,它允许你通过简单易用的 Web 界面,就可以管理你的 Linux 服务器。它允许你管理用户,组,磁盘配额,创建文件…

c++ auto用法_不想写表达式的类型?试试auto吧

作者:守望,Linux应用开发者,目前在公众号【编程珠玑】 分享Linux/C/C/数据结构与算法/工具等原创技术文章和学习资源。前言你以为我说的自动变量类型auto吗?非也,我们知道C语言中其实也有auto关键字,它和早…

浅谈内存映射I/O(MMIO)与端口映射I/O(PMIO)的区别

最近在看NVMeDirect和SPDK的源码,觉得有必要梳理一下MMIO和PMIO的区别。关于MMIO和PMIO,维基百科上是这么讲滴, Memory-mapped I/O (MMIO) and port-mapped I/O (PMIO) (which is also called isolated I/O) are two complementary methods o…

linux sftp密码错误,linux个别用户sftp坏掉,验证密码后卡住, 大概是什么问题?...

问题描述linux个别用户sftp坏掉,验证密码后卡住, 大概是什么问题?所有采用sftp的软件都不能用了winsshfs 点击mount后就卡住xftp 连接验证结束后也卡住sublimeText3 的sftp插件也不好用了突然发生的情况之前一直用着都没有问题一直正常使用 只…

c语言 结构体_C语言 技能提升 系列文章 (三)结构体

今天,来跟大家聊一聊C语言中的结构体。在C语言的各种数据类型中,结构体最特别,因为它是可以被程序员定义的,它的特点是非常的灵活。定义struct defined_name{type_name field_name;};结构体内部的成员可以是任意类型的数据&#x…

基于@FeignClient注解实现两个微服务之间接口的调用(简单)

场景需求:微服务A中的接口input需要调用微服务B中接口的output数据。 实现:使用feign实现即可。 微服务B中的接口: 步骤一:微服务A中编写一个接口,该接口就是调用微服务B的接口;需要在接口上添加FeignClien…

spring boot 自动跳转登录页面_徒手撸一个扫码登录示例工程

徒手撸一个扫码登录示例工程不知道是不是微信的原因,现在出现扫码登录的场景越来越多了,作为一个有追求、有理想新四好码农,当然得紧跟时代的潮流,得徒手撸一个以儆效尤本篇示例工程,主要用到以下技术栈qrcode-plugin&…

inputstreamreader未关闭会导致oom_ThreadLocal 一定会导致内存泄露?

在面试的时候,ThreadLocal作为高并发常用工具经常会被问到。而面试官比较喜欢问的问题有以下两个:1、ThreadLocal是怎么实现来保证每个线程的变量副本的。2、ThreadLocal的内存泄露是怎么产生的,怎么避免内存泄露。首先我们来看第一个问题&am…

keras保存模型_TF2 8.模型保存与加载

举个例子:先训练出一个模型import 接下来第一种方法:只保留模型的参数:这个有2种方法:model.save_weights("adasd.h5")model.load_weights("adasd.h5") model.predict(x_test)model.save_weights(./checkpoin…

第一章 Burp Suite 安装和环境配置

Burp Suite是一个集成化的渗透测试工具,它集合了多种渗透测试组件,使我们自动化地或手工地能更好的完成对web应用的渗透测试和攻击。在渗透测试中,我们使用Burp Suite将使得测试工作变得更加容易和方便,即使在不需要娴熟的技巧的情…

mysql57服务无法启动_将mysqld.service服务加入到systemctl

在开始安装二进制MySQL的时候感觉都还挺好,就是在启动服务的时候比较麻烦,一开始是在Centos6下的感觉也没有什么费劲的;但是在Centos7下面还是有点不太适应,不过还好用用就熟悉了;说明一下,我的安装目录在/usr/local/m…

linux raid autodetect,软raid的建立

1 增加磁盘并分区(修改id)fdisk /dev/sdbCommand (m for help): pDisk /dev/sdb: 8589 MB, 8589934592 bytes255 heads, 63 sectors/track, 1044 cylindersUnits cylinders of 16065 * 512 8225280 bytesDevice Boot Start End Blocks Id System/dev/sd…

c语言for循环的省略写法,C语言两种for循环写法分析

每个C程序员都知道同一个for循环语句可以有两种写法:A: for (i 0; i B: for (i cnt; i > 0; i--){ }前几天,DEBUG的时候, 发现采用A写法的代码反汇编出来有BUG.当时没有时间记录,环境也没有保存下来.今天尝试重现,又没来出现上次的问题...很奇怪.很久很久以前也听说过这两…

python文字游戏 生成数字菜单_pygame游戏之旅 游戏中添加显示文字

本文为大家分享了pygame游戏之旅的第5篇,供大家参考,具体内容如下 在游戏中添加显示文字: 这里自己定义一个crash函数接口: def crash(): message_diaplay(You Crashed) 然后实现接口函数message_display(text) def message_diapl…

springboot netty给特定客户端推送_Spring Boot 又升级了?2.0 你搞懂了吗?!

【小宅按】作为知名互联网公司都在用的技术,Spring Boot 2.0 的更新引起了很大的关注,本文将分为三部分解读 2.0 的更新:第一类,基础环境升级;第二类,默认软件替换和优化;第三类,新技…

OSI七层模型与TCP/IP五层模型详解

博主是搞是个FPGA的,一直没有真正的研究过以太网相关的技术,现在终于能静下心学习一下,希望自己能更深入的掌握这项最基本的通信接口技术。下面就开始搞了。 一、OSI参考模型 今天我们先学习一下以太网最基本也是重要的知识——OSI参考模型。…