JVM
2021-04-14 16:14:35 14 举报
AI智能生成
JVM
作者其他创作
大纲/内容
数据区
线程共享
堆<br>
新生代
老年代
生命周期长的内存对象
永久代
存放Class和 Meta(元数据)的信息
GC 不会在主程序运行期对永久区域进行清理
随着类的加载增多,容易导致OOM
<font color="#c41230">Java8中被移除</font>
被元数据区取代<br>
方法区<br>
存储
JVM加载的类信息<br>
常量、静态变量<br>
即时编译器编译后的代码
回收
常量池的回收
类型的卸载
常量池
编译期生成的各种字面量和符号引用
线程私有
程序计数器<br>
不会发生OOM<br>
虚拟机栈<br>
Java 方法执行的内存模型<br>
方法执行入栈,堆内创建对象且栈内引用
方法结束出栈,堆内存对象引用失效
内容
局部变量表
存放方法参数和方法内定义的局部变量
操作数栈
一个后入先出栈(LIFO)
动态链接
方法返回地址
本地方法区<br>
为本地方法服务<br>
垃圾回收
MinorGC<br>
触发条件
新分配对象内存不够<br>
复制算法
步骤
1.eden、servicorFrom中活对象 复制到 ServicorTo,年龄+1
2.清空 eden、servicorFrom
3.ServicorTo 和 ServicorFrom 互换
MajorGC<br>
触发条件
1.MinorGC之后内存不够<br>
2.新建大对象无法找到足够大的内存空间<br>
3.年龄达到15岁<br>
GC算法
标记清除算法
FullGC<br>
触发条件
1.调用System.gc时,系统建议执行Full GC,但是不必然执行
2.老年代空间不足<br>
3.方法区空间不足<br>
4.通过Minor GC后进入老年代的平均大小大于老年代的可用内存<br>
标记算法
<font color="#000000">引用计数法</font><br>
适用场景
内存不太充裕
实现
计数器的管理(自增/自减)
人工完成
Objective-C
C++里使用COM
自动管理
CPython
C++11的std::shared_ptr
引用计数存储
侵入式的存在对象内
CPython:把引用计数存在每个受自动内存管理的Python对象的对象头里
存在对象外面
C++11标准库里的std::shared_ptr
可达性分析
适用场景
内存充裕
GC roots<br>
虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中(Native)引用的对象
原理
GC Roots引用链<br>
对象的生死状态只能批量的被识别出来,然后批量释放死对象<br>
不可达不等于可回收<br>
GC算法
标记清除算法<br>
问题:内存碎片化
应用:MajorGC
老年代垃圾回收<br>
复制算法<br>
问题:内存减半<br>
应用:MinorGC
新生代垃圾回收<br>
标记整理算法<br>
将存活对象移向内存的一端<br>
应用:
垃圾收集器
CMS
目的:获取最短回收停顿时间为目标的收集器<br>
回收算法:基于“标记-清除”<br>
原理:垃圾回收线程和系统工作线程尽量同时执行的模式<br>
步骤<br>
1.初始标记<br>
STW
标记出所有GC Roots直接引用的变量
2.并发标记<br>
对老年代所有对象进行GC Roots追踪(最耗时)
3.重新标记
STW
重新标记第二阶段新创建的对象
4.并发清理<br>
垃圾回收线程数
默认:(CPU核数+3)/4
存在的问题
1.消耗CPU资源
2.浮动垃圾:并发清理阶段进去老年代的对象
3.并发清理垃圾回收失败
4.内存碎片问题
导致
频繁的GC
参数设置开启
GC之后停止所有工作线程,进行碎片整理
执行多少次GC之后进行内存碎片整理
触发时机<br>
老年代内存占用达到一定比例<br>
1.6默认92%<br>
参数可设置<br>
并发垃圾回收失败
自动用Serial Old垃圾回收器替代CMS
生产实践中要避免
ParNew
多线程垃圾回收
默认线程数和CPU核数一致
STW
G1
特点
将Java堆内存分为多个大小相等的Region<br>
目标是不超过 <font color="#000000">2048个Region</font>
Region的大小必须是2的倍数
一般保持默认即可
也可通过参数设置指定
新生代和老年代是逻辑概念<br>
<font color="#000000"><b>可以设置垃圾回收的预停顿时间</b></font><br>
停顿可控
追踪每个Region中可以回收的对象大小和预估时间
尽量缩短垃圾回收对系统的影响时间
在有限的时间内回收尽可能多的垃圾对象
原理
<font color="#c41230">管理无限大内存</font>
ZGC
特点
并发
着色指针
读屏障
内存参数
参数含义
-Xms:Java堆内存大小
-Xmx:Java堆内存的最大大小
-Xmn:堆内存新生代大小
-XX:PermSize:永久代大小
-Xss:每个线程的栈内存大小
每个线程的栈空间是固定
进程内所有线程的栈空间不固定
系统应用设置JVM参数
java -Xms ... -jar App.jar
占机器内存比例
参考值
8G-5440M
实际并没有标准
实战
1.预估系统业务量,访问量
2.推算系统每秒并发,推算每秒内存占用
类加载
步骤
1.加载<br>
2.链接<br>
1.验证<br>
2.准备<br>
3.解析<br>
3.初始化<br>
机制
双亲委派
好处
加载器<br>
启动类加载器
lib目录中的类库<br>
拓展类加载器(ExtClassLoader)<br>
lib\ext目录中类库<br>
系统类加载器(AppClassLoader)<br>
ClassPath的类库<br>
自定义类加载器<br>
一些思考
自定义类会被编译和加载吗
会被编译
不会被加载,JVM类加载器会加载特定包下的类
自定义类加载器加载自定义类
JVM限制了我们的类不能以java, java.lang来开头。<br>要绕开这个机制,需要自己写native方法去完成类加载过程<br>
JavaBridge
PhpJavaServlet
PhpCGIServlet
存在的意义
跨平台
1.Java 源文件—->编译器—->字节码文件<br>
2.字节码文件—->JVM—->机器码
GC调优
工具
jstat
1.找到JAVA进程PID<br>
2.jstat -gc PID
新生代对象增长的速率
年轻代触发频率
年轻代的耗时
.........
其他命令
jstat -gccapacity
jstat -gcnew PID
jstat -gcold PID
主要观察参数
年轻代
Eden区的对象增长速率
Young GC频率多高
一次Young GC 耗时
Young GC之后多少对象存活
老年代
老年代的对象增长速率
Full GC频率
一次Full GC耗时
jmap
jmap -head PID
jmap -histo PID
使用jmap生成堆内存转储快照
使用jhat在浏览器中分析堆转出快照
MAT
主要分析dump文件
阿里云ECS
线上系统监控
Zabbix
Open-Falcon
jstat
频繁Full GC的几种表现
机器CPU负载过高
频繁Full GC报警
系统无法处理请求或者处理很慢
排查OOM
命令:jmap -dump:format=b,file=heap.bin<br>file:保存路径及文件名<br>pid:进程编号(windows通过任务管理器查看,linux通过ps aux查看)<br>dump文件可以通过MemoryAnalyzer(MAT)分析查看,可以查看dump时对象数量,内存占用,线程情况等。
让JVM在遇到OOM(OutOfMemoryError)时生成Dump文件<br>-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/heap/dump
当你没有dump文件的时候,也没有明显日志的时候,GC也无异常的时候挂掉,<br>可以在操作系统中开启参数 ulimit -c<br>如果不等于0会在java进程挂掉的时候阻塞一段时间,留给操作系统保留现场,生成一个core dump,然后通过工具转换成jvm dump文件进行分析
实战
好文
生产事故排查
案例1
事故现场
堆内存正常,栈内存正常
机器内存一直上升,容器杀掉进程
没有OOM
排查过程
确定原因:响应式编程代码,线程资源不受JVM管控,程序没有主动释放
解决方案
代码主动释放内存占用
案例2
事故现场
机器内存足够,应用没有任何日志异常,上线就oom
而且重启运行后就正常,可以维持运行一个月左右
排查过程
解决方案
面试
16G内存的机器,长连接的应用如果用CMS参数怎么配置<br>
G1平时怎么用?说说原理
JVM内存模型、栈帧的局部变量表有哪些内容
0 条评论
下一页