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…

iOS11最新隐私信息访问列表

今天早上应用出现拍照上传闪退的紧急bug,才发现在iOS11中,隐私权限配置又发生了改变,将原来的相册访问权限分开了,现在有读写两种权限。 iOS11访问权限列表 隐私数据对应key值提示语相册(读)NSPhotoLibraryUsageDescription"…

linux make教程,Linux下makefile的一个简单框架

目录结构tree.|-- Makefile-- src|-- Makefile|-- bar| |-- Makefile| -- bar.c-- foo|-- Makefile-- foo.c3 directories, 6 files顶层Makefile# Makefile for top directory# phony target.PHONY: all debug release clean#all: release#debug:$(MAKE) -C src debug#release:…

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

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

开机启动

shell:startup 转载于:https://www.cnblogs.com/baiquan/p/7691968.html

linux飞行模式自动开机,解决 win10飞行模式 无限自动开关 无法关闭

Linux 中 Vi 编辑器的简单操作Linux 中 Vi 编辑器的简单操作 Vi 编辑器一共有3种模式:命名模式(默认),尾行模式,编辑模式.3种模式彼此需要切换. 一.进入 Vi 编辑器的的命令 vi filename //打开或新 ...WPF好看的进度条实现浅谈(效果有点类似VS2012安装界面)为了界面友好,一般的…

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…

【转】asp.net Core 系列【一】——创建Web应用

ASP.NET Core 中的 Razor 页面介绍 Razor 页面是 ASP.NET Core MVC 的一个新功能,它可以使基于页面的编码方式更简单高效。 若要查找使用模型视图控制器方法的教程,请参阅 ASP.NET Core MVC 入门。 ASP.NET Core 2.0 必备组件 安装 .NET Core 2.0.0 或更…

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

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

Linux lua 性能,systemTab动态分析linux下lua性能

参考ngx-sample-lua-bt现代linux 动态追踪技术 主要是基于 ebpfsystemtap 是 动态追踪的前端, 技术原理是 编译一个 类似c的脚本 生成 内核模块, 来监控用户空间的lua程序对openResty的脚本改造两点,1: 去掉nginx相关函数的 probe…

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

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

OpenGL, GLSL, DirectX, HLSL中的矩阵存储形式

(原文地址:http://alvincc-tech.blogspot.com/2010/10/opengl-glsl-directx-hlsl.html) OpenGL, GLSL, DirectX, HLSL中的矩阵存储形式 OpenGL: 按列存储矩阵(column-major)。调用API形成的矩阵用来和一个列向量相乘,矩阵在左&am…

linux cpp标准库,标准库以及标准头文件

源文件通过编译可以生成目标文件(例如 GCC 下的 .o 和 Visual Studio 下的 .obj),并提供一个头文件向外暴露接口,除了保护版权,还可以将散乱的文件打包,便于发布和使用。实际上我们一般不直接向用户提供目标文件,而是将…

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

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