栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

51.整理JVM

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

51.整理JVM

JVM调优的原则?
  1. 不要为了调优而调优,首先确定的应该是项目的架构与代码已经没有优化的空间了,再考虑进行JVM的调优工作,不能指望通过JVM调优来使得性能有一个质的飞越
  2. 从三个属性中(吞吐量,延迟,内存)中选择两个进行JVM调优,称之为调优3选2,在处理吞吐量和延迟问题时,GC能使用的内存越大,应用运行也就越流畅,这也叫GC内存最大化原则
什么情况下需要进行调优?
  1. Full GC数量频繁,GC停顿时间超长(超过1s)
  2. 应用出现OOM异常或者吞吐量下降,响应性能不高,
  3. 应用CPU占用过高,内存占用过高
吞吐量和低延迟?

吞吐量:代码时间/(代码时间+垃圾回收时间),吞吐量越高,算法越好

低延迟:STW越短,响应时间越好,算法越好,目的在于缩短或者完全消除因垃圾收集器引起的停顿

一个GC算法只可能针对于以上两个目标之一或者尝试找到一个折中方案,吞吐量优先的垃圾回收器有Parallel的年轻代和老年代版本,响应时间优先的垃圾回收器有CMS和G1

常用性能调优工具和常用参数

常用工具:jvisualvm,jconsole,MAT(提示可能内存泄露的点)

常用参数解释:

  • -Xms:JVM启动时申请的初始Heap大小
  • -Xmx:JVM运行时可申请的最大Heap值,为了避免每次GC后JVM重新分配内存,一般设置为同一个值
  • -Xmn:设置Heap中新生代的大小,通过Xms-Xmn可以得到老年代的大小
  • -Xss:设置每个线程可使用的栈大小
  • -XX:TraceClassLoading/TraceClassUnLoading可以在日志中追踪类加载和卸载的情况
CPU占用过高的排查流程?
  • top命令查看出cpu最高的进程pid(这里也可以用jps -l命令)
  • [ps -mp 进程号 -o THREAD,tid,time]定位具体的线程(这里也可以使用top -Hp pid)
  • 使用[printf "%xn" 线程id]将需要的线程转换为16进制格式
  • 使用[jstack 进程ID|grep 16进制线程id -A60]打印出前60行信息
ps常用参数:
-A    显示所有进程(等价于-e)(utility)
-a    显示一个终端的所有进程,除了会话引线
-N    忽略选择。
-d    显示所有进程,但省略所有的会话引线(utility)
-x    显示没有控制终端的进程,同时显示各个命令的具体路径。dx不可合用。(utility)
-p    pid 进程使用cpu的时间
-u    uid or username 选择有效的用户id或者是用户名
-g    gid or groupname 显示组的所有进程。
-f    全部列出,通常和其他选项联用。如:ps -fa or ps -fx and so on.
-l    长格式(有F,wchan,C 等字段)
-j    作业格式
-o    用户自定义格式
-m    显示所有的线程
-H    显示进程的层次(和其它的命令合用,如:ps -Ha)(utility)
-a    显示同一终端下的所有程序
-A    列出所有的进程
-w    显示加宽可以显示较多的资讯
-au   显示较详细的资讯
-aux  显示所有包含其他使用者的进程
-e    显示所有进程,环境变量
-f    全格式
-h    不显示标题
-l    长格式
-w    宽输出
内存占用过高排查流程?
  • 查找进程Id: top查看内存占用过高的进程pid
  • [jmap -heap pid]:查看JVM堆内存的分配情况
  • [jmap -histo:live pid|head -n 100]:查看占用内存比较多的存活对象
什么情况会抛出OOM?OOM之前会发生什么

满足以下两个条件中的任意一个会产生OOM

  • JVM的98%时间都用于内存回收
  • 每次回收的内存小于2%

OOM之前的现象:

  • 每次垃圾回收的时间越来越长,且full gc的次数越来越多
  • 老年代的内存越来越大,每次full gc后,只有少量的内存被释放掉
线上死锁排查?
  • [jps -l]查找到可能有问题的进程id
  • 执行[jstack -F 进程id]命令
  • 如果说可以远程连接到JVM,可以使用jconsole或者jvisualvm,以图形化界面检测是否死锁

jstack命令:

-l:打印关于锁的信息

-F:当-l没有响应的时候,强制打印栈信息

-m:答应jaba和native c/c++框架所有栈信息

JVM的主要组成部分及其作用?

JVM包含两个子系统和两个组件,子系统为:类装载和执行引擎,组件为运行时数据区与本地接口

  • 类装载:根据给定的类全限定类名,装载class文件到运行时数据区的方法区
  • 执行引擎:将字节码翻译成底层系统指令,交由cpu去执行
  • 本地接口:与本地方法库交互,是其他编程语言交互的接口
  • 运行时数据区域:jvm的内存

运行时数据区:java虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个不同的数据区

  • 程序计数器:当前线程所执行的字节码的行号指示器,利用它可以完成分支,跳转,线程恢复,循环等工作
  • 虚拟机栈:存储局部变量表,操作数栈,动态链接,方法出口等信息
  • 本地方法栈:虚拟机栈服务java方法,本地方法栈服务native方法
  • 堆:被线程共享的一块区域,几乎所有的对象实例都在这里分配
  • 方法区:用于存储已经被虚拟机加载的类信息,常量,静态常量,即时编译后的代码等数据
堆和栈的区别?

堆的物理地址分配对象是不连续的,因此性能会慢一些,栈使用的是数据结构中的栈,先进后出,物理地址分配是连续的所以性能快

堆所分配的内存是在运行期间确认的,大小不固定,一般远远大于栈,栈分配的内存在编译时就要确定

对存放对象的实例和数组,栈存放的是局部变量,操作数栈,返回结果

堆对于整个程序是可见的,栈对于线程可见,生命周期与线程相同

Java是否会存在内存泄露问题?

有,当长生命周期的对象持有短生命周期对象的引用就会发生,经过短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致无法回收

垃圾收集器?
  • Serial收集器(复制算法): 新生代单线程收集器,标记和清理都是单线程,优点是简单高效;
  • ParNew收集器 (复制算法): 新生代收并行集器,实际上是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现;
  • Parallel Scavenge收集器 (复制算法): 新生代并行收集器,追求高吞吐量,高效利用 CPU。吞吐量 = 用户线程时间/(用户线程时间+GC线程时间),高吞吐量可以高效率的利用CPU时间,尽快完成程序的运算任务,适合后台应用等对交互相应要求不高的场景;
  • Serial Old收集器 (标记-整理算法): 老年代单线程收集器,Serial收集器的老年代版本;
  • Parallel Old收集器 (标记-整理算法): 老年代并行收集器,吞吐量优先,Parallel Scavenge收集器的老年代版本;
  • CMS(Concurrent Mark Sweep)收集器(标记-清除算法): 老年代并行收集器,以获取最短回收停顿时间为目标的收集器,具有高并发、低停顿的特点,追求最短GC回收停顿时间。
  • G1(Garbage First)收集器 (标记-整理算法): Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。此外,G1收集器不同于之前的收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代,老年代),而前六种收集器回收的范围仅限于新生代或老年代。

标记清除:从GC roots中找到存活对象,然后清除其他没有被标记的对象

标记整理:在标记清除的基础上,将存活对象压缩到内存的一端,避免了内存碎片问题

复制算法:把内存划分为两个区域,每次只使用其中的一个区域,垃圾收集时,把存活对象复制到另一个区域,清空当前块的内存

分代收集:根据对象的存活周期划分内存,一般包括年轻代,老年代和永久代

CMS垃圾收集器?

牺牲了吞吐量来获得最短回收停顿时间的垃圾回收器,对于要求服务响应速度的应用,这种垃圾回收器非常合适,使用-XX:+UseConcMarkSweepGC来使用

CMS的步骤分为:

  • 初始标记:会标记GC Roots直接关联的对象,这个过程会发生stw,因为只标记一层所以速度很快,该过程是单线程
  • 并发标记:该过程不会停止用户线程,做的是从GC Roots向下追溯标记可达对象的工作
  • 重新标记:该过程中保证的是可达对象一定被标记了,需要stw
  • 并发清理:不会stw,并发的回收不可达的对象,这个过程用户线程会不断的产生垃圾,变为浮动垃圾,留给下一次GC处理

优点:

  • 将stw的时间降到最低,给电商网站的用户带来最好的体验

缺点:

  • 内存碎片问题
  • 浮动垃圾问题
  • 有时候会占用大量的cpu时间,当cms运行过程中预留的空间不够用,会使用serial old来进行老年代垃圾回收导致停顿时间变长
简述分代垃圾回收器是怎么工作的?

分代有两个分区:老年代(2/3)和新生代(1/3)

新生代使用的复制算法,Eden,To Survivor,From Survivor.默认占比为8:1:1,执行流程如下:

  • Eden+From->To,并且使对象的年龄+1,大于15就被丢进老年代,大对象也会直接进入老年代
  • 清空Eden与From
  • From和To交换身份

内存分配策略:

  • 对象优先在Eden区分配,当Eden没有足够空间,发起一次Minor GC
  • 大对象直接进入老年代,参数-XX:PretenureSizeThreshold
  • 长期存活的对象进入老年代
  • 空间担保机制:在Minor GC发生之前,JVM要预估老年代是否能容纳Minor GC后新生代晋升到老年代的存活对象,以确定是否需要提前触发GC回收老年代空间
  • 动态年龄判断:新生代对象年龄没有达到阈值,但是新生代存活对象的年龄达到某个值且这些对象大小的总和大于survivor空间的一半或者说survivor空间不足以容纳这些对象,对象直接进入老年代
类装载的过程?

加载:根据查找路径找到相应class文件然后导入,在方法区生成类信息,在堆中添加class对象

验证:检查加载的class文件的正确性

准备:给类中的静态变量,或者是final修饰的变量分配内存空间

解析:将符号引用转为直接引用

初始化:对静态变量和静态代码块执行初始化

对象创建过程?
  • java在new一个对象的时候,会先查看所属类有没有被加载到内存中,如果没有会先进行类的加载过程
  • 申请对象内存:指针碰撞或者空闲列表
  • 成员变量赋默认值
  • 设置对象头(哈希码,GC分带年龄,偏向锁id,指向类的元数据的指针)
  • 调用构造方法init
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/872582.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号