JVM也叫java虚拟机,特点是它的跨平台性,Java语言使用Java虚拟机屏蔽了与具体平台相关的信息。
Java虚拟机在运行Java程序时,会管理着一块内存区域,JVM内存模型可分为五个部分:堆区、方法区、虚拟机栈、本地方法栈、程序计数器
1.堆:该内存区域是jvm虚拟机管理的内存中最大的一块内存,它存放了对象实例及数组
2.方法区:是各个线程共享的内存区域,用于已被虚拟机加载的类型信息、常量、静态变量、编译器代码缓存等
3.虚拟机栈:它保存方法的局部变量、方法返回地址和一些额外的附加信息
4.本地方法栈:它保存的是Native方法中的局部变量、方法返回地址和一些额外的附加信息
5.程序计数器:程序中分支、循环、跳转、异常处理、线程恢复等基础功能要用到计数器支持
jvm一大特色就是自动内存管理,它负责对堆内存中对象的分配与回收。一个对象从加载到jvm,再到被垃圾回收器GC清除,经过如下步骤:
1.用户创建一个对象,jvm首先需要到方法区去找对象的类信息。
2.jvm实例化对象,首先在堆中先创建一个对象,然后分配在堆内存中新生代的Eden区,然后经过依次新生代的的垃圾收集动作(Minor GC),
对象如果存活,就会被移动到From survivor空间,再次执行Minor GC,如果对象还存活,此时会将对象移动到To Survivor区,同时把该对象的年龄+1,此时再把From Survivor 和 To Survivor指针交换,用来保证下一次MinorGC时,to survivor区还是空的。
如果对象被复制的次数达到15(-XX:+MaxTenuringThreshold),那么该对象会被移动到老年代。另外如果单个Survivor区已经被占用了 50%( -XX:TargetSurvivorRatio),那么大年龄对象也会被移动老年代。老年代对象存活一段时间后,如果发现对象不可达GcRoot,而且此时老年代空间比率已经超过了阈值将触发FullGC,随后将被垃圾收集器回收。
JVM内存异常一般是程序bug导致的,典型的有:死循环、使用无界队列等,也可以通过定制JVM运行参数来提高Java应用程序的运行性能
1.一般情况下如果发现java进程负载过高,我们这个时候就会进行相关的排查。
2.第一步我们会通过top命令查看java进程所占用的CPU和内存,如果长期处于高负载状态,我们先查看GC日志(-verbose:gc 可以输出GC情况)。
3.gc日志中我们定时查看触发GC前后的内存空间是否一直处于居高不下缓慢上升的状态,说明可能出现了无法被回收的内存空间。
5.这个时候,我们可以通过top -Hp命令列出该java进程占用cpu和内存最高的线程(记下线程ID)。然后通过jstack命令打印当前java进程的线程堆栈信息
6.根据线程堆栈信息的调用找到出问题的代码,然后分析出现异常的原因。
JVM 内存指标有如下:
1.查看堆存储快照,分析内存的占用情况
2.查看堆各区域的内存增长是否正常
3.查看是哪个区域导致的GC
4.查看GC后能否正常回收到内存
JVM GC指标有:
1.查看每分钟GC时间是否正常
2.查看每分钟YGC次数是否正常
3.查看FGC次数是否正常
4.查看单次FGC时间是否正常
5.查看单次GC各阶段详细耗时,找到耗时严重的阶段
6.查看对象的动态晋升年龄是否正常
针对上述指标查找问题,一般有:
1.代码bug:升级修复bug。典型的有:死循环、使用无界队列。
2.不合理的JVM参数配置,优化 JVM 参数配置,典型的有:年轻代内存配置过小、堆内存配置过小、元空间(方法区)配置过小。