JVM性能优化实战
2021-10-18 11:54:10 0 举报
JVM虚拟机内存模型(JDK1.7,1.8方法区替换成元数据空间)
作者其他创作
大纲/内容
定位系统的大对象分析到这里,就很简单了,我们只需要采用之前给大家介绍的jmap工具,通过后台jstat工具观察系统,什么时候发现老年代里突然进入了几百MB的大对象,就立马用jmap工具导出一份dump内存快照。
Java堆空间
Jsp类加载器
局部变量表
函数3
tomcat的配置,在http请求头中会开辟一个空间max-http-header-size: 10000000
本地方法栈: 本地方法, 一般都由C语言写的,native类型的method
4,5,6、每次young gc后有多少对象是存活下来的和进入老年代利用2、中可知,young gc的触发频率使用:jstat -gc pid XX(触发young gc的时间周期) 10这样观察,老年代的变化,即可知道;同时可以知道老年代的增长速率
Java 栈 非共享的
栈帧main()局部变量表、动态链接库、返回值
函数1
Minor GC之前会先去检查,老年代是否内存足够(对应下方第5点)
线程的方法栈如何发生内存溢出
新生代
3、解析符号引用替换成直接引用
还有一个参数,“-XX:G1MixedGCLiveThresholdPercent”,他的默认值是85%,意思就是确定要回收的Region的时候,必须是存活对象低于85%的Region才可以进行回收,把85%的对象都拷贝到别的Region,这个成本是很高的。
Java堆内存存放我们创建的各种对象比如: 局部变量有一个局部变量是对象时,此时栈帧里的局部变量表,是只有一个地址引用,指向了堆内存中的实际对象
堆内存如何发生内存溢出
如果有GC Roots对象,然后是强引用,则不会,否则软引用、弱引用都可能会被回收finalize()在被回收前调用
2020-12-24
JVM性能优化的点
Serial Old垃圾回收器-单线程-已停用(最坏方案)
CMS-多线程并发
新生代GC如何优化我们首先应该给整个JVM的堆区域足够的内存,比如我们在这里就给了JVM超过5G的内存,其中堆内存有4G的内存。合理设置“-XX:MaxGCPauseMills”参数
WebApp类加载器
Common类加载器
......etc
一开始的引用计数法已经被淘汰了可达性算法
5、使用
BI:商业智能系统
eden
垃圾回收器(ParNew)
方法区 共享的 jdk1.6/1.7 就是永久区;jdk1.8 变成了元数据区
1、metaspace 512MB或者256MB2、堆内存 机器内存的一半3、栈内存推荐1MB,这样1000个线程大概占用1GB,例如tomcat就得设置几百个线程。-XX:ThreadStackSize=1m,通过这个参数设置JVM的栈内存为1MB。
经过多次的垃圾回收后,仍然存活的对象,会从新生代 转移到 老年代
应用程序类加载器
“-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFaction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0”
jhat -port 7000 dump.hprof// 在浏览器中分析堆转出的快照
垃圾回收器
1、系统背景2、核心业务流程3、高峰运行压力4、机器部署5、每秒请求压力6、每秒使用内存压力
设置栈内存大小:一般默认512kb到1MB差不多
栈帧本地方法: native修饰的方法局部变量表、动态链接库、返回值
本地方法栈
mixed GC如何优化减缓新生代gc后进入老年代的速度主要两个条件导致:新生代gc过后存活对象过多无法放入Survivor区域,以及动态年龄判定规则
CMS垃圾回收器:标记清理算法
G1垃圾回收器的过程讲解
扩展类加载器
-Xms3072M -Xmx3072M -Xmn1536M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:HandlePromotionFailure”
对象优先分配到新生代
老年代的垃圾回收参数设置
使用MAT打开一个内存快照之后,在MAT上有一个工具栏,里面有一个按钮,他的英文是:Leak Suspects,就是内存泄漏的分析。
会发生内存溢出的几个区域1、存放类相关信息及常量池等的永久代2、每个线程对应的虚拟机方法栈3、放实际对象实例的堆空间
1、新生代对象增长的速率jstat -gc PID 1000 10这行命令,他的意思就是每隔1秒钟更新出来最新的一行jstat统计信息,一共执行10次jstat统计
栈帧3
制定统一的jvm参数模板
虚拟机方法栈
线程每个线程有自己的程序计数器&&虚拟机栈
“-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFaction=92”
-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
回收对象目标:同时回收新生代和老年代的对象
混合回收都是基于复制算法进行的。还有一个参数,就是“-XX:G1HeapWastePercent”,默认值是5%,一旦空闲出来的Region数量达到堆内存的5%,此时立即停止混合回收。
PC寄存器(程序计数器)每个线程私有的空间。指向当前正在被执行的指令,如果是本地方法,则为undefined
“-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC”
2、扩展类加载器(lib\\ext目录)Extension ClassLoader
排查工具MAT
JVM调优
G1有一个参数:\"-XX:InitiatingHeapOccupancyPercent\",表示如果老年代占据了堆内存45%时,就会尝试触发一个新生代+老年代的混合回收阶段。Mixed GC
模拟:jstat -gc 51464 1000 1000
什么是内存溢出
1、验证验证字节码文件是否合法
设置永久代大小,一般几百MB就足够了
额外的参数优化:优化Full GC的性能,进一步降低Full GC的时间“-XX:+CMSParallelInitialMarkEnabled”,这个参数会在CMS垃圾回收器的“初始标记”阶段开启多线程并发执行。“-XX:+CMSScavengeBeforeRemark”,这个参数会在CMS的重新标记阶段之前,先尽量执行一次Young GC。“-XX:+CMSParallelRemarkEnabled“:在重新标记的时候多线程执行,降低STW;“-XX:CMSInitiatingOccupancyFraction=92“和“-XX:+UseCMSInitiatingOccupancyOnly“配套使用,如果不设置后者,jvm第一次会采用92%但是后续jvm会根据运行时采集的数据来进行GC周期,如果设置后者则jvm每次都会在92%的时候进行gc;“-XX:+PrintHeapAtGC“:在每次GC前都要GC堆的概况输出
tomcat打破双亲委派机制的类加载器执行顺序
栈帧1
初始内存布局对机器上的JVM,分配4G给堆内存,其中新生代默认初始占比为5%,最大占比为60%,每个Java线程的栈内存为1MB,元数据区域(永久代)的内存为256M,此时JVM参数如下:“-Xms4096M -Xmx4096M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M “-XX:G1NewSizePercent”参数是用来设置新生代初始占比的,不用设置,维持默认值为5%即可。“-XX:G1MaxNewSizePercent”参数是用来设置新生代最大占比的,也不用设置,维持默认值为60%即可。GC停顿时间设置在G1垃圾回收器中有一个至关重要的参数会影响到GC的表现,就是“-XX:MaxGCPauseMills”,他的默认值是200毫秒
启动类加载器
SimpleObject类的相关信息&方法实现&常量类eg: static fieldstatic methodclassfieldmethod...运行时常量池,包括字符串字面量&数字常量
JVM
jvm调优建议:1、增加Survivor区的大小,让Minor GC后的对象进入Survivor区中,避免进入老年代
JVM 发生OOM的问题及解决方案
字节码执行引擎执行代码
估计一个对象,大概占多少内存,每秒大概new多少个对象,计算多久之后会导致Minor GC
新系统开发完后,jvm参数的设置
-Xms3072M -Xmx3072M -Xmn1536M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M”
老年代:长期存在的对象
7、Full GC的触发时机和耗时触发频率:知道了老年代对象的增长速率即可计算full gc的触发频率每次耗时:利用jstat的FGC和FGCT计算得出
2、类加载
1、年轻代gc时,eden区和survivor区的大小比例,默认8:1:12、大内存机器的新生代GC,指定垃圾回收器G13、老年代的GC问题:减缓minor gc后进入老年代的速度说白了:内存分配,参数设置,垃圾回收器选择
jmap -heap PID
目的:设置好参数:XX:MaxGCPauseMills但需要借助大量内存分析工作和gc日志工具
User.javaCarModel.javaCarBrand.java
所以一般会长期被GC Roots引用,这种对象一般不会太多,大概最多一个系统就几十MB这种对象。
1、在线教育系统2、在线听课的互动环节3、每小时120w请求,每秒3000请求4、5台4核8G的机器,每台每秒600请求分担5、每秒600请求压力6、分析每秒在互动环节产生600个对象使用的内存大小,eg:每个请求5kb,总共3MB
老年代
类加载子系统: 负责从文件系统或者网络中加载Class信息。
使用jmap和jhat摸清线上系统的对象分布
jdk1.6
加载的类信息存放于一块称为方法区的内存空间
Java 栈: 非共享的, 是一块 线程私有的内存空间。线程执行每一次函数调用,都会有一个对应的栈帧被压入当前的java栈每一个Java虚拟机线程都有一个私有的Java栈
Survivor2
直接内存
-Xms4096M -Xmx4096M -Xmn3072M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0--可根据自身情况,增加下面参数禁用System.gc() // -XX:+DisableExplicitGC
3、应用程序类加载器(加载ClassPath)环境变量下所指定路径的类Application ClassLoader
复制算法缺点:对内存的使用效率太低,只有50%可用引入Eden区和Survivor区后,利用率到了90%
1、jstat -gccapacity PID:堆内存分析2、jstat -gcnew PID:年轻代GC分析,这里的TT和MTT可以看到对象在年轻代存活的年龄和存活的最大年龄3、jstat -gcnewcapacity PID:年轻代内存分析4、jstat -gcold PID:老年代GC分析5、jstat -gcoldcapacity PID:老年代内存分析6、jstat -gcmetacapacity PID:元数据区内存分析
Serial垃圾回收器-单线程-已停用(最坏方案)
1、启动类加载器(lib目录下)Bootstrap ClassLoader
From区10%
1、初始标记2、并发标记3、最终标记4、混合回收
OOM异常的监控及定位、排查、分析、纠错
-Xms3072M -Xmx3072M -Xmn1536M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8”
引入实际项目:G1垃圾回收期调优
jmap -histo PID// 了解当前内存到底是哪个对象占用了大量的内存
方法区: 共享的
survivor区域from&to是大小,空间完全相同的两个内存空间。专门为垃圾回收的复制算法而存在
标记整理算法缺点:比新生代的垃圾回收算法慢了起码10倍
频繁Full GC的几种常见原因1、系统承载高并发请求,或者处理数据量过大,导致Young GC很频繁,而且每次Young GC过后存活对象太多,内存分配不合理,Survivor区域过小,导致对象频繁进入老年代,频繁触发Full GC。2、系统一次性加载过多数据进内存,搞出来很多大对象,导致频繁有大对象进入老年代,必然频繁触发Full GC3、系统发生了内存泄漏,莫名其妙创建大量的对象,始终无法回收,一直占用在老年代里,必然频繁触发Full GC4、Metaspace(永久代)因为加载类过多触发Full GC5、误调用System.gc()触发Full GC
回收失败,可能空闲region不足,则触发Full GC
直接内存:Java的NIO允许Java程序使用直接内存,直接内存是Java堆外的、直接向系统申请的内存空间。读写频繁的场合可能会考虑使用直接内存
ParNew-多线程并发
G1会去追踪每个Region中可以回收对象的大小和预估时间。(选择最少回收时间和最多回收对象的Region区域进行垃圾回收)在垃圾回收的时候,尽量把垃圾回收对系统造成的影响控制在你指定的时间范围内,同时在有限的时间内尽量回收尽可能多的垃圾对象
日处理上亿数据量的计算系统
栈帧2
G1垃圾回收器-统一收集新生代和老年代
原理:自定义类加载器,继承ClassLoader类,重写类加载的方法,然后重写loadClass,不先由父类加载。Tomcat中的自定义的类加载器就是WebappClassLoader
-XX:+UseG1GC指定G1垃圾回收器之后,会自动用堆大小除以2048,JVM最多可以用2048个Region,每个Region的大小必须是2的倍数,如1MB,2MB,4MB如果手动指定Region大小,即为\"-XX:G1HeapRegionSize=1MB\"
记录指令位置
0、加载类加载器加载字节码
MAT可以直观的发现哪个对象占用了大内存
2,3、young gc的触发频率和耗时触发频率:根据1、中可以算出每次耗时:利用jstat的YGC和YGCT计算得出
默认JVM参数配置模板:-XX:NewSize=5242880 -XX:MaxNewSize=5242880 -XX:InitialHeapSize=10485760 -XX:MaxHeapSize=10485760 -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10485760 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
Eden区
“-Xms4096M -Xmx4096M -Xmn3072M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFaction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSParallelInitialMarkEnabled -XX:+CMSScavengeBeforeRemark -XX:+DisableExplicitGC -XX:+PrintGCDetails -Xloggc:gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/app/oom”
tenured
程序计数器
回收新生代
垃圾回收算法(复制算法)
Full GC优化的前提是Minor GC的优化;Minor GC的优化的前提是合理的分配空间(Eden区和Survivor区,大小及比例);合理的分配内存空间的前提是,对系统运行期间的内存模型进行预估
-XX:MetaspaceSize=512m-XX:MaxMetaspaceSize=512m两个大原因1、直接用了默认参数,几十MB导致永久代大小太小;推荐是512MB2、使用了动态代理技术,eg:cglib,生成了很多代理类3、大量使用了反射技术,Method.invoke会产生额外对象进入metaspace
老年代内存不够新生代对象进入时,触发Full GC
帧数据区
配置发生OOM的时候,自动dump内存快照-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/usr/local/app/oom
Eden区 80%实例对象最新进入的内存区域,满了之后就会把垃圾回收后剩下的实例对象,分配到一块空的Survivor区每次垃圾回收可能存活下来的对象就1%,所以在设计的时候就留了一块100MB的内存空间来存放垃圾回收后转移过来的存活对象
垃圾回收算法
Catalina类加载器
15次Minor GC后,还存活1、新生代垃圾回收之后,存活对象太多,导致大量对象直接进入老年代2、特别大的超大对象直接不经过新生代就进入老年代3、动态对象年龄判断机制4、空间担保机制
压测之后,使用jstat工具进行分析1、Eden区的对象增长速率多快2、Young GC频率多高3、一次Young GC多长耗时4、Young GC过后多少对象存活5、老年代的对象增长速率多高6、Full GC频率多高7、一次Full GC耗时
执行引擎: 核心组件,负责执行虚拟机的字节码
操作数栈
直接内存NIO中可以通过allocateDirect这种API直接分配内存空间
使用jstat命令分析jstat -gc pid1、S0C:这是From Survivor区的大小2、S1C:这是To Survivor区的大小3、S0U:这是From Survivor区当前使用的内存大小4、S1U:这是To Survivor区当前使用的内存大小5、EC:这是Eden区的大小6、EU:这是Eden区当前使用的内存大小7、OC:这是老年代的大小8、OU:这是老年代当前使用的内存大小9、MC:这是方法区(永久代、元数据区)的大小10、MU:这是方法区(永久代、元数据区)的当前使用的内存大小11、YGC:这是系统运行迄今为止的Young GC次数12、YGCT:这是Young GC的耗时13、FGC:这是系统运行迄今为止的Full GC次数14、FGCT:这是Full GC的耗时15、GCT:这是所有GC的总耗时16、CCSC:压缩类空间大小17、CCSU:压缩类空间使用大小
专门存放大对象的Region,G1认为超过一个Region的50%时,即为大对象;大对象即不存放在新生代的region,也不存放在老年代的region
回收老年代
1、躲过15次Minor GC后,进入老年代,这里具体多少次,可以通过JVM参数\"-XX:MaxTenuringThreshold\
Full GC优化
大内存机器:且业务需要实时性优先考虑G1垃圾回收期大内存机器,Young GC可能会导致长时间的停顿
函数2
Metaspace区域如何发生内存溢出
利用jstat工具需要得到的信息1、新生代对象增长的速率2、young gc的触发频率3、young gc的耗时4、每次young gc后有多少对象是存活下来的5、每次young gc过后有多少对象进入了老年代6、老年代对象增长的速率7、full gc的触发频率8、full gc的耗时
方法区,又叫永久代(1.8之前)元数据空间(1.8及之后)存放类的信息,一些类似常量池的东西
1、搭建监控平台2、客服或运营提醒
刚开始,默认新生代对堆内存的占比是5%,可通过“-XX:G1NewSizePercent”来指定这个比例,默认占比不会超过60%,可通过参数指定:“-XX:G1MaxNewSizePercent”
函数4
垃圾回收线程
JVM堆内存相关的部分核心参数1、-Xms:Java堆内存的大小2、-Xmx:Java堆内存的最大大小3、-Xmn:Java堆内存中的新生代大小,扣除新生代剩下的就是老年大的内存大小4、-XX:PermSize:永久代大小5、-XX:MaxPermSize:永久代最大大小6、-Xss:每个线程的栈内存大小---JDK8之后,没有永久代,换成元数据空间5、-XX:MetaspaceSize6、-XX:MaxMetaspaceSize-- -- 命令启动java -Xms512M -Xmx512M -Xmn256M -Xss1M -XX:PermSize=128M -XX:MaxPermSize=128M -jar App.jar-- wap-carjava -Dfile.encoding=utf-8 -Xmx1024M -jar $APP_NAME --spring.profiles.active=$PROFILES_ACTIVE > $LOG_FILE 2>&1 --Spring Boot其实就是启动的时候可以加上JVM参数,Tomcat就是在bin目录下的catalina.sh中可以加入JVM参数
jdk1.7或jdk1.8
4、自定义类加载器
To区10%
垃圾回收线程和系统工作系统尽量同时执行的模式来处理的。CMS执行一次垃圾回收的过程分为4个阶段:1、初始标记(出现Stop The World,但是很快)直接引用的GC Roots2、并发标记(追踪老年代所有对象是否从根源上被GC Roots引用)3、重新标记(出现Stop The World,但是很快)重新标记在第二阶段里新创建的一些对象4、并发清理(耗时,但是并发)-- CMS 会消耗CPU资源CMS默认启动的垃圾回收线程的数量是(CPU核数 + 3)/ 4。Concurrent Mode Failure问题 产生浮动垃圾,需要“-XX:CMSInitiatingOccupancyFaction”参数可以用来设置老年代占用多少比例的时候触发CMS垃圾回收,JDK 1.6里面默认的值是92%。如果此时8%的空间不够了,即浮动垃圾进入老年代的内存空间大于老年代整个内存空间的8%时,会发生 Concurrent Model Failure,此时就会自动用“Serial Old”垃圾回收器替代CMS,就是直接强行把系统程序“Stop the World”,重新进行长时间的GC Roots追踪,标记出来全部垃圾对象,不允许新的对象产生-- 针对标记-清理算法,产生的内存碎片问题CMS有一个参数是“-XX:+UseCMSCompactAtFullCollection”,默认就打开了--还有一个参数是“-XX:CMSFullGCsBeforeCompaction”,这个意思是执行多少次Full GC之后再执行一次内存碎片整理的工作,默认是0,---- 导致发生Full GC的时机“-XX:CMSInitiatingOccupancyFaction”参数刨除掉上述几种情况,如果老年代可用内存大于历次新生代GC后进入老年代的对象平均大小,但是老年代已经使用的内存空间超过了这个参数指定的比例,也会自动触发Full GC。
计算一个对象占用的内存大小对象头:64位系统占16字节,32位系统占8字节;int:4字节long:8字节double:8字节
Region即可能当前属于新生代,新一次回收之后变成属于老年代,由G1自动控制
2021-10-18
1、编译成class后,打包
系统程序
from
Survivor1
cpu飙升的原因1、开了很多个线程并发执行负载很重的任务2、频繁地触发了Full GC
执行字节码指令
解决的目的:ParNew&&CMS都会导致的问题:Stop The World(尽可能的减少耗时)
尽量让每次Young GC后的存活对象小于Survivor区域的50%,都留存在年轻代里。尽量别让对象进入老年代。尽量减少Full GC的频率,避免频繁Full GC对JVM性能的影响。
建议配置
Shared类加载器
6、卸载
-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5
新生代内存不够分配对象时,触发Minor GC
公司级别的JVM参数模板
栈帧4
jar包/war包User.classCarModel.classCarBrand.class
跟踪类的加载卸载-jvm参数配置“-XX:TraceClassLoading -XX:TraceClassUnloading”使用反射会导致元数据空间使用内存变多
打印JVM GC日志1、-XX:+PrintGCDetils:打印详细的gc日志2、-XX:+PrintGCTimeStamps:这个参数可以打印出来每次GC发生的时间3、-Xloggc:gc.log:这个参数可以设置将gc日志写入一个磁盘文件
2、准备分配内存空间,分配初始化
动态年龄判定规则,如果一旦发现某次新生代GC过后,存活对象超过了Survivor的50%此时就会判断一下,比如年龄为1岁,2岁,3岁,4岁的对象的大小总和超过了Survivor的50%,此时4岁以上的对象全部会进入老年代,这就是动态年龄判定规则
其余和原来一样,也是有Eden区和Survivor区的区分,然后用复制算法垃圾回收,只是这里可以设定目标GC的停顿时间,可以用参数设置“-XX:MaxGCPauseMills”默认是200ms
什么时候触发垃圾回收
java -jar启动一个jvm进程
Survivor区
类加载器ClassLoader
线上频繁Full GC的几种表现1、机器CPU负载过高2、频繁Full GC报警3、系统无法处理请求或者处理过慢
混合回收阶段:回收老年代,回收新生代,回收大对象(允许执行多次混合回收,断断续续的Stop The World)
根本原因:瞬时产生了大量对象,垃圾回收器在进行Minor GC时,大量对象都还在被直接或间接引用1、系统承载高并发请求,因为请求量过大,导致大量对象都是存活的,所以要继续放入新的对象实在是不行了,此时就会引发OOM系统崩溃2、系统有内存泄漏的问题,就是莫名其妙弄了很多的对象,结果对象都是存活的,没有及时取消对他们的引用,导致触发GC还是无法回收,此时只能引发内存溢出,因为内存实在放不下更多对象了
新生代:很快就要被回收的对象
Java堆是在虚拟机启动的时候建立,它是Java程序最主要的内存工作区域。几乎所有的Java对象实例都存放在Java堆中。堆空间是所有线程共享的,这是一块与Java应用密切相关的内存空间。
G1垃圾回收器:
对象首次初始化,都会存放在eden区域
类加载子系统
特点:1、把Java堆内存拆分为多个大小相等的Region2、可以让我们设置一个垃圾回收的预期停顿时间
垃圾回收系统: 对方法区、Java堆、直接内存进行回收
1、估算系统核心接口每秒需要多少次请求;2、每次请求会创建多少个对象;3、每个对象大概多大;4、每秒钟会占用多少的内存空间;5、你期望的几分钟触发一次young gc
新生代的垃圾回收参数设置
分析多长时间会触发新生代GC
双亲委派机制
类加载器流程
总结1、survivor区要设置大小能够50%也满足新生代young gc后存放,避免频繁进入老年代;2、大对象的创建问题,还有阈值,避免大对象直接进入老年代;3、System.gc()禁用,避免让jvm尝试使用full gc
G1垃圾回收器参数设置
初步排查full gc的问题1、内存分配不合理2、存在内存泄露等问题3、永久代里的类太多
ParNew垃圾回收器:复制算法
恢复运行创建对象
场景eg:new CarModel();new CarBrand()或者是包含main方法的主类
4、初始化父类静态变量->父类静态代码块->父类构造方法
线上系统的监控和优化两种方法1、监控工具:Zabbix、Open-Falcon之类的工具2、jstat周期写入日志文件
一般默认都是设置1MB的方法栈内存大小根本原因:方法递归调用,层次过深
to
G1它本身是这样的一个运行原理,他会根据你预设的gc停顿时间,给新生代分配一些Region,然后到一定程度就触发gc,并且把gc时间控制在预设范围内,尽量避免一次性回收过多的Region导致gc停顿时间超出预期。
收藏
0 条评论
下一页