当前位置: 首页 > news >正文

JVM (四)GC过程

一。概述


程序计数器、虚拟机栈、本地方法栈都是随线程生灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理,因此,内存垃圾回收主要集中于Java堆和方法区中
GC整体流程示意图:
① 年轻代对象的移动
1,新创建的对象分配到eden区;
2,eden区满了触发minor gc,eden存活的对象被复制到from区(年龄+1),不存活的对象被回收;
3,当eden区再次满了,eden和from区的存活对象被复制到to区,from和to区交换。如果to区放不下,则晋升到老年代
4,几次minor gc后,当对象的年龄达到阈值(-XX:MaxTenuringThreshold默认是15)之后,就会被从年轻代Promotion到老年代;
② minor gc和major gc的时机
1. 在新生代申请内存空间不足的时候触发垃圾回收;
2. 判断老年代剩余空间是否大于年轻代所使用的内存
    1. 老年代剩余空间 > 年轻代所使用空间,直接进行Minor GC;
    2. 老年代剩余空间 < 年轻代所使用空间,这个时候要看有没有设置担保机制(-XX:HandlePromotionFailure)
        1. 设置了担保机制,则比较每一次Minor GC后晋升到老年代的平均大小和老年代的剩余空间大小:
            1. 平均晋升对象大小 < 老年代剩余空间大小,这个时候就执行Minor GC;
            2. 平均晋升对象大小 > 老年代剩余空间大小,这个时候就先执行Major GC;
        2. 没设置担保机制,则先进行一次Major GC(防Minor GC后老年代放不下晋升对象);
至于minor gc和major gc如何执行,那就是不同垃圾收集器做的事情了。

二。垃圾分类


三。对象存活判断


判断对象是否存活一般有两种方式:
引用计数
每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,无法解决对象相互循环引用的问题
可达性分析(Reachability Analysis):
从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。不可达对象。
在Java语言中,GC Roots包括
* 虚拟机栈中引用的对象;
* 方法区中类静态变量引用的对象;
* 方法区中常量引用的对象;
* 本地方法栈中JNI引用的对象;

四。垃圾收集算法


标记 -清除算法

是最基础的收集算法,是因为后续的收集算法都是基于这种思路。
分为“标记”和“清除”两个阶段:
  1. 标记出所有需要回收的对象;
  2. 统一回收掉所有被标记的对象;
优点:简单快捷;
缺点:内存碎片化严重

复制算法

将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
每次对其中的一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为原来的一半,持续复制长生存期的对象则导致效率降低。
优点:内存碎片化问题得到部分解决;
缺点:内存的有效使用率太低。

标记-整理算法

标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
优点:解决内存碎片化问题并且内存利用率大大提高;
缺点:内存需要不断地变动,效率变低。

分代收集算法

严格来说并不是一种思想或理论,而是融合上述3种基础的算法思想,而产生的针对不同情况所采用不同算法的组合。
GC分代的基本假设:绝大部分对象的生命周期都非常短暂,存活时间短。
Java堆分为新生代和老年代,根据各个年代特点采用适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要复制少量存活对象就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清除”或“标记-整理”算法来进行回收。

五。垃圾收集器


如果说收集算法是内存回收的方法论,垃圾收集器就是内存回收的具体实现。
详见:JVM 垃圾收集器

六。Stop-The-World


在垃圾回收过程中经常涉及到对对象的挪动,导致需要对对象引用进行更新。为了保证引用更新的正确性,Java将暂停所有其他的线程,这种情况被称为“Stop-The-World”,导致系统全局停顿,会对系统性能存在影响。

在JVM启动参数的GC参数里加上-XX:+PrintGCApplicationStoppedTime,可以把全部的JVM停顿时间(不只是GC),打印在GC日志里。这个参数,可以打出几乎一切的停顿……
2016-08-22T00:19:49.559+0800: 219.140: Total time for which application threads were stopped: 0.0053630 seconds

相关文章:

  • Linux环境各种软件安装配置
  • 时间轴、流程类时间轴绘制
  • 7-1RT-Thread邮箱
  • LabVIEW在高校中的应用
  • 技术干货分享:初识分布式版本控制系统Git
  • 大学专业选择的岔路口:计算机相关专业的前景与适配性
  • DBSCAN 算法【python,机器学习,算法】
  • Web前端职业描述:编织数字世界的绚丽画卷
  • 360数字安全:2024年4月勒索软件流行态势分析报告
  • MySQL常用命令(Linux环境)
  • 2024年,计算机相关专业还值得选择吗?
  • 如何实现观察者模式和发布-订阅模式?
  • 高压电工作业历年试题分享(含答案)
  • web鼠标前端设置:深入探索与个性化定制
  • 不是所有的硬盘柜都叫“安全专家”,但它做到了!
  • 收藏网友的 源程序下载网
  • docker-consul
  • ECMAScript入门(七)--Module语法
  • JAVA之继承和多态
  • js ES6 求数组的交集,并集,还有差集
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • uni-app项目数字滚动
  • webpack入门学习手记(二)
  • 力扣(LeetCode)965
  • 实现菜单下拉伸展折叠效果demo
  • 微信公众号开发小记——5.python微信红包
  • 我感觉这是史上最牛的防sql注入方法类
  • 学习ES6 变量的解构赋值
  • 由插件封装引出的一丢丢思考
  • HanLP分词命名实体提取详解
  • #nginx配置案例
  • #QT(QCharts绘制曲线)
  • #每天一道面试题# 什么是MySQL的回表查询
  • (C11) 泛型表达式
  • (Pytorch框架)神经网络输出维度调试,做出我们自己的网络来!!(详细教程~)
  • (Redis使用系列) SpirngBoot中关于Redis的值的各种方式的存储与取出 三
  • (ZT)出版业改革:该死的死,该生的生
  • (八)c52学习之旅-中断实验
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (附源码)springboot助农电商系统 毕业设计 081919
  • .cn根服务器被攻击之后
  • .gitignore
  • .Net CoreRabbitMQ消息存储可靠机制
  • .NET delegate 委托 、 Event 事件
  • .NET建议使用的大小写命名原则
  • .net中应用SQL缓存(实例使用)
  • /usr/bin/perl:bad interpreter:No such file or directory 的解决办法
  • [20170728]oracle保留字.txt
  • [CSAWQual 2019]Web_Unagi ---不会编程的崽
  • [CSS]盒子模型
  • [godot] 采用状态机时,如何处理攻击时移动?如“冲撞”
  • [JavaScript]_[初级]_[不使用JQuery原生Ajax提交表单文件并监听进度]
  • [JDK工具-6] jmap java内存映射工具
  • [LeetCode] 19. 删除链表的倒数第 N 个结点