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

JVM实战(15)——Full GC调优

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析

阶段4、深入jdk其余源码解析

阶段5、深入jvm源码解析

一、简介

本章将会讲解一个频繁Full GC的案例,示例来自于JVM基础篇中的亿级流量系统。我们先来回顾下案例。

1.1 案例背景

假设现在生产环境有一套“数据计算系统”,不停地从MySQL等各类数据源提取数据到内存中进行计算,系统是分布式的。

每个节点(机器)每分钟执行100次操作(提取数据并计算,每次操作耗时10s),每次操作1万条数据,每条数据大小为1KB左右,每次操作的数据大小就是10MB:

每台机器的配置是4核8G,JVM分配4G内存,其中新生代1.5G,老年代1.5G。

1.2 内存使用模型估算

每次操作会在Eden区分配10MB对象,以1分钟100次操作来算,那么Eden区1分钟内就会被占满:

二、Full GC调优

每个计算任务处理1万条数据耗时10s,假设此时80个计算任务都结束了,还有20个计算任务共计200MB正在计算中,那么此时200MB对象是存活的,不会被Young GC回收掉:

2.1 扩Survivor

由于任何一块Survivor区只有100MB,所以新生代中这存活的200MB对象会晋升到老年代,然后清空Eden:

如此反复,大约经过7分钟后,也就是经历了7次Young GC,此时大概有1.4G对象在老年代中:

再经过1分钟,也就是第8分钟结束时,新生代又满了,此时发现老年代可用空间已经不足(剩余100MB),比历代平均的晋升对象大小(200MB)要小,所以会直接触发一次Full GC。

Full GC会先把老年代的垃圾回收了(假设能全部回收),然后执行一次Young GC,此时Eden区存活的对象会进入老年代:

按照这种情况,每隔8分钟左右就会发生一次Full GC。Full GC的性能是很差的,所以必须进行优化,最基本的优化思路就是扩大Survivor区的内存,比如扩到200MB。这样基本就能避免对象频繁进入老年代,将Full GC频率降低到几个小时一次。

2.2 采用大内存

上述的示例,是假设系统每天的负载是1亿请求, 如果请求量再扩大十倍呢?

参照首节的内存使用模型来估算, 每秒中会有100MB左右的数据进入Eden,那么Eden会在10s内就被塞满,触发Young GC 。

计算任务本身就耗时10s左右,所以直接后果就是,即使进行了Young GC,可能也只能回收掉几百MB数据。那每隔10s,就有1G左右的数据进入老年代,那下一个10s又来1G数据,就会触发Full GC。最终的结果就是每分钟触发好几次Full GC,对于系统来说就是灾难。

所以,针对这个问题,首先要做的显然就是扩内存,比如换成16核32G的机器,Eden分配16G,Survivor各分配2G。那么按每秒加载100MB数据进内存来算,需要2分钟左右才会触发一次YoungGC,而每次Young GC的存活对象也就是几百MB,Survivor区足够容纳。这就避免了对象频繁进入老年代,触发Full GC。

那么,针对这种大内存的机器,我们是否需要用G1作为垃圾回收器呢?

对于本示例中的系统是不需要的,因为这种数据计算系统一般都是离线的,也就是说不和用户直接交互,所以哪怕每隔2分钟进行一次Young GC,每次Young GC耗时1s也没什么影响。

相关文章:

  • uniapp 编译后文字乱码的解决方案
  • Ps:何时需要转换为智能对象
  • 招投标系统是Electron的纯内网编辑Office Word,可以设置部分区域可编辑,其他的地方不能编辑吗?
  • MyBatis第三课
  • day-09 删除排序链表中的重复元素
  • GAMES101:作业7记录
  • 【Go】excelize库实现excel导入导出封装(三),基于excel模板导出excel
  • Linux shell编程学习笔记39:df命令
  • Go语言使用gosseract 库来进行图像文字识别,识别出来的中文是乱码的?如何解决?
  • linux项目部署(jdk,tomcat,mysql,nginx,redis)
  • python学习笔记10(选择结构2、循环结构1)
  • 【Linux】Linux系统编程——Linux目录结构
  • 【驱动】TI AM437x(内核调试-02):dynamic 动态打印调试
  • 微信小程序Canvas画布绘制图片、文字、矩形、(椭)圆、直线
  • Spring整理-Spring框架的国际化
  • 【译】JS基础算法脚本:字符串结尾
  • 【附node操作实例】redis简明入门系列—字符串类型
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • chrome扩展demo1-小时钟
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • Iterator 和 for...of 循环
  • Java 网络编程(2):UDP 的使用
  • java概述
  • js操作时间(持续更新)
  • k8s 面向应用开发者的基础命令
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • Python语法速览与机器学习开发环境搭建
  • spring cloud gateway 源码解析(4)跨域问题处理
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 从零开始的无人驾驶 1
  • 从零开始在ubuntu上搭建node开发环境
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 悄悄地说一个bug
  • 为什么要用IPython/Jupyter?
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • Python 之网络式编程
  • raise 与 raise ... from 的区别
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • #07【面试问题整理】嵌入式软件工程师
  • #ubuntu# #git# repository git config --global --add safe.directory
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (附源码)springboot优课在线教学系统 毕业设计 081251
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理 第13章 项目资源管理(七)
  • (一)基于IDEA的JAVA基础1
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .NET 中什么样的类是可使用 await 异步等待的?
  • .Net中ListT 泛型转成DataTable、DataSet
  • @converter 只能用mysql吗_python-MySQLConverter对象没有mysql-connector属性’...
  • @EventListener注解使用说明
  • @PreAuthorize注解
  • [ vulhub漏洞复现篇 ] Hadoop-yarn-RPC 未授权访问漏洞复现
  • [ABP实战开源项目]---ABP实时服务-通知系统.发布模式
  • [ACTF2020 新生赛]Include