JVM
2026-02-10 16:51:37 0 举报
AI智能生成
JVM
作者其他创作
大纲/内容
加载
Loading<br>
类加载器
Bootstrap
加载lib/rt.jar charset.jar 等核心类,C++实现
Extension
加载扩展jar包,jre/lib/ext/*.jar,或由-Djava.ext.dirs指定
App
加载classpath指定内容
CustomClassLoader
自定义ClassLoader
加载流程
双亲委派机制
1、安全
2、减少资源消耗
自定义ClassLoader
1、extend ClassLoader
2、override findClass ---> defineClass(byte[] -> Class clazz)<br>
LazyLoading
混合执行 编译执行 解释执行<br>
检测热点代码:-XX:CompileThreshold = 10000
Linking
Verification
验证文件是否符合JVM规定
Preparation
静态成员变量赋默认值
Resolution
将类、方法、属性等符号引用解析为直接引用 常量池中的各种符号引用解析为指针、偏移量等内存地址的直接引用 <br>
Initializing
用类初始化代码 ,给静态成员变量赋初始值
Java内存模型
共享内存模型(JMM)<br>
原子性、可见性、有序性<br>
volatile
字节码层面
ACC_VOLATILE<br>
JVM层面
volatile内存区的读写都加屏障
StoreStoreBarrier<br>volatile 写操作<br>StoreLoadBarrier<br>LoadLoadBarrier<br>volatile 读操作<br>LoadStoreBarrier
OS和硬件层面
lock指令或MESI
synchronized
字节码层面
方法上:ACC_SYNCHRONIZED<br>同步块:monitorenter monitorexit
JVM层面
C C++ 调用了操作系统提供的同步机制
OS和硬件层面
x86 : lock cmpxchg / xxx
Java内存区域
PC
程序计数器(Program Counter Register),线程私有<br>
Java虚拟机栈
描述
每个方法在执行的同时都会创建一个栈帧(Stack Frame,是方法运行时的基础数据结构),<br>线程私有的,它的生命周期与线程相同<br>
包含内容<br>
局部变量表
操作数栈
动态链接
方法返回地址
本地方法栈<br>
虚拟机使用到的 Native 方法服务<br>也会抛出 StackOverflowError 和 OutOfMemoryError 异常<br>
方法区
各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
运行时常量池
堆
内存分代模型
jdk1.7:Perm Generation(永久代)
Class信息<br>必须指定大小
method area(方法区)逻辑概念
字符串常量
jdk1.8:MetaSpace(元数据区)
Class信息<br>可以不指定大小,受限于物理内存
method area(方法区)逻辑概念
OldGen(老年代)
大对象会直接分配至老年代
Eden区MinorGC超过一定阈值的对象会到老年代
老年代满了后会触发FullGC=MajorGC+MinorGC
EdenGen(新生代)<br>
分为Eden区+2个Survivor区<br>
1、YoungGC后,大部分对象会被回收,存活对象进入S0区<br>2、再次GC后,eden区活着的对象+S0 ----> S1<br>3、再次GC后,eden区或者的对象+S1 ----> S0<br>4、对象标记的次数达到设置的阈值15(CMS垃圾回收器为6)进入OldGen<br>5、Survivor区装不下,直接进入OldGen<br>
垃圾回收
垃圾定位
引用计数算法<br>
不用,循环引用问题
根可达算法(GCRoots)
1、虚拟机栈(栈帧中的本地变量表)中引用的对象<br>
因为当前线程正在执行该方法,则该方法中的所有变量引用的对象不可被回收
2、方法区中的类静态属性引用的对象
3、方法区中常量引用的对象
4、本地方法栈中JNI(即一般说的Native方法)中引用的对象
垃圾回收算法
标记清除(mark sweep)<br>
位置不连续、产生碎片、效率偏低(两遍扫描)<br>
拷贝(coping)
没有碎片,浪费空间<br>
标记压缩(mark compact)<br>
没有碎片,效率偏低(两遍扫描,指针需要调整)<br>
垃圾回收器
Serial<br>
年轻代 串行回收
拷贝(coping)
PS<br>
年轻代 并行回收
拷贝(coping)
ParNew<br>
年轻代 配合CMS的并行回收
拷贝(coping)
SerialOld
老年代 串行回收
标记压缩(mark compact)
ParallelOld
老年代 并行回收
标记压缩(mark compact)<br>
CMS
老年代 并发回收
标记清除(mark sweep)
初始标记->并发标记->重新标记->并发清除<br>
问题:内存碎片<br>出现Concurrent Mode Failure或PromotionFailed,会使用SerialOld单线程回收老年区<br>解决方案:<br>–XX:CMSInitiatingOccupancyFraction 92%,让CMS保持老年代足够的空间<br>
G1
标记压缩(mark compact)
组合参数设置
-XX:+UseSerialGC = Serial New (DefNew) + Serial Old
-XX:+UseParNewGC = ParNew + SerialOld
-XX:+UseConcMarkSweepGC = ParNew + CMS + Serial Old
-XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8默认) 【PS + SerialOld】
-XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old
-XX:+UseG1GC = G1
JVM常用参数
GC常用参数
-Xmn -Xms -Xmx -Xss 年轻代 最小堆 最大堆 栈空间<br>
-XX:+UseTLAB 使用TLAB,默认打开
-XX:+PrintTLAB 打印TLAB的使用情况
-XX:TLABSize 设置TLAB大小
-XX:+DisableExplictGC System.gc()不管用 ,FGC
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC
-XX:+PrintGCTimeStamps
-XX:+PrintGCApplicationConcurrentTime (低) 打印应用程序时间
-XX:+PrintGCApplicationStoppedTime (低) 打印暂停时长
-XX:+PrintReferenceGC (重要性低) 记录回收了多少种不同引用类型的引用
-verbose:class 类加载详细过程
-XX:+PrintVMOptions<br>
-XX:+PrintFlagsFinal -XX:+PrintFlagsInitial 必须会用
-Xloggc:opt/log/gc.log<br>
-XX:MaxTenuringThreshold 升代年龄,最大值15
锁自旋次数 -XX:PreBlockSpin 热点代码检测参数-XX:CompileThreshold 逃逸分析 标量替换 ... 这些不建议设置
Parallel常用参数
-XX:SurvivorRatio
-XX:PreTenureSizeThreshold 大对象到底多大
-XX:MaxTenuringThreshold
-XX:+ParallelGCThreads 并行收集器的线程数,同样适用于CMS,一般设为和CPU核数相同
-XX:+UseAdaptiveSizePolicy 自动选择各区大小比例
CMS常用参数
-XX:+UseConcMarkSweepGC
-XX:ParallelCMSThreads CMS线程数量
-XX:CMSInitiatingOccupancyFraction 使用多少比例的老年代后开始CMS收集,<br>默认是68%(近似值),如果频繁发生SerialOld卡顿,应该调小,(频繁CMS回收)
-XX:+UseCMSCompactAtFullCollection 在FGC时进行压缩
-XX:CMSFullGCsBeforeCompaction 多少次FGC之后进行压缩
-XX:+CMSClassUnloadingEnabled
-XX:CMSInitiatingPermOccupancyFraction 达到什么比例时进行Perm回收
GCTimeRatio 设置GC时间占用程序运行时间的百分比
-XX:MaxGCPauseMillis 停顿时间,是一个建议时间,GC会尝试用各种手段达到这个时间,比如减小年轻代
G1常用参数
-XX:+UseG1GC
-XX:MaxGCPauseMillis 建议值,G1会尝试调整Young区的块数来达到这个值
-XX:GCPauseIntervalMillis ?GC的间隔时间
-XX:+G1HeapRegionSize 分区大小,建议逐渐增大该值,1 2 4 8 16 32。 <br>随着size增加,垃圾的存活时间更长,GC间隔更长,但每次GC的时间也会更长 ZGC做了改进(动态区块大小)
G1NewSizePercent 新生代最小比例,默认为5%
G1MaxNewSizePercent 新生代最大比例,默认为60%
GCTimeRatio GC时间建议比例,G1会根据这个值调整堆空间
ConcGCThreads 线程数量
InitiatingHeapOccupancyPercent 启动G1的堆空间占用比例
调优
内存泄漏(memory leak)<br>内存溢出(out of memory)
吞吐量:用户代码时间 / (用户代码时间 + 垃圾回收时间)<br>响应时间:STW越短,响应时间越好
吞吐量优先:科学计算、数据挖掘,一般选择(PS+PO)<br>响应时间优先:网站GUI API(1.8 G1)
方法
1、选择回收器组合
2、计算内存需求
3、选定CPU(越高越好)
4、设定年代大小、升级年龄
5、设定日志参数
-Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
每天产生一个日志文件
6、观察日志情况
0 条评论
下一页