当前位置 博文首页 > 闫玉林的博客:深入了解Java虚拟机:JVM调优

    闫玉林的博客:深入了解Java虚拟机:JVM调优

    作者:[db:作者] 时间:2021-08-29 16:10

    初探

    • Java代码运行,Java源文件(.java)-- > javac编译 -->字节码文件(.class)–> JVM --> 计算机底层指令和硬件
    • jvm,Java虚拟机,不同的操作系统有不同版本的JVM虚拟机。JVM从软件层面,隐藏了底层技术实现的复杂性,屏蔽了不同机器不同操作系统的底层细节,保证Java代码,编写一次,到处执行。Write Once,Run Anywhere.

    JDK、JRE与JVM

    • Java,是一种面向对象的编程语言,属于高级语言。1995年,Java之父,詹姆斯·高斯林(高司令),Oak --> Java。
    • JDK Java开发工具包,包含JRE。
    • JRE Java运行时环境,包含JVM。
    • JVM Java虚拟机,包含运行时数据区、执行引擎、本地库接口等。

    内存结构

    • 堆和方法区,是线程共享区
    • 栈,本地方法栈、程序计数器,是线程独占区

    • new的对象都放在堆里
    年轻代(占堆内存的1/3)
    • Eden,占年轻代的80%,程序数据先往Eden里写入,当Eden内存用完时,触发Minor GC,垃圾对象被清理,非垃圾对象被复制到Survivor区域,这些对象的分代年龄加1。
    • Survivor,占年轻代的20%,分为2部分,各占10%;当触发Minor GC 时,Survivor区域里的垃圾对象也会被清理,非垃圾对象在Survivor的两个分区相互移动,这些对象的分代年龄继续加1。
    • S0 1/3 * 10%
    • S1 1/3 * 10%
    老年代(占堆内存的2/3)
    • 大对象直接进入老年代,可以通过 -XX:PretenureSizeThreshold 设置,超过这个值,对象直接在Old区分配内存。这个参数只在Serial和ParNew2个收集器下有效。
    • 长期存活的对象进入老年代。当Survivor区里的非垃圾对象分代年龄达到阈值(默认15,可通过 -XX:MaxTenuringThreshold 来设置),就会将这些对象移入老年代。
    • 对象动态年龄判断。Minor GC时,当一批对象的总大小大于Survivor区内存大小的50%(可通过 -XX:TargetSurvivorRatio指定),会被放入Old区分配内存。
    • Minor GC后,Survivor区放不下,多余的部分也会放入到Old区域。
    • 当老年代内存被占用完,就会触发full GC。
    • 当full GC 后,old区域空间还是不够分配,程序抛出异常OutOfMemoryError: Java heap space。

    • 栈,遵循后进先出原则
    • 一个方法,分配一个栈帧
    • 局部变量表,存储方法的局部变量,存储变量的指针
    • 操作数栈,存储变量的值
    • 动态链接
    • 方法出口,方法运行结束,返回主线程

    程序计数器

    • 当前线程正在运行的代码的位置(行号)

    方法区

    • 存储类信息,类的常量和静态变量

    本地方法栈

    • native 本地方法,调用本地系统的接口或者本地外部c程序的接口

    垃圾回收机制

    • GC Roots根节点:线程栈的本地变量,静态变量、本地方法栈的变量等等
    • 讲“GC Roots”对象作为起点,从这些节点开始搜索引用的对象,找到的对象标记为非垃圾对象,其余未标记的对象都是垃圾对象。
    • Eden满时触发Minor GC
    • Old满时触发full GC

    性能监控工具

    jconsole

    • java启动命令添加jvm参数 -XX:+HeapDumpOnOutOfMemoryError 可以输出内存溢出时的堆栈

    jmap

    • 查看堆内存使用情况
    • 命令 : jmap -heap

    jvisualvm

    • java 6,7,8自带的jvm调优工具
    • java9及以后,就停止使用java VisualVM了,改用Graal VisualVM了
    • 查看heap堆得Eden、Old,需要安装一个Visual GC插件。安装方法很简单,找到jdk目录的bin下面,打开jvisualvm.exe,然后 工具-》插件,选择Visual GC即可,在线安装如果不行,可以先下载再安装。
      jvisualVM界面

    性能调优案例

    概念

    • STW : Java中Stop-The-World机制.
    • 执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起,只执行垃圾收集。这是Java中一种全局暂停现象,会给程序使用者带来非常不好的体验(卡顿)。
    • jvm调优,就是为了减少full GC 的次数,减少STW时间,发挥出机器原本就有的性能,使程序更加稳定高效的运行,最终给程序使用者带来更好的使用体验。

    部分JVM参数

    • Xms 设置java程序启动时堆内存128M(默认为物理内存1/64,且小于1G)
    • Xmx 设置最大堆内存256M,超出后会出现 OutOfMemoryError(默认为物理内存1/64,且小于1G)
    • Xmn 堆内存,新生代区域大小
    • Xss 设置线程栈的大小 1M(默认1M)
    • XX:MinHeapFreeRatio=40:设置堆空间最小空闲比例(默认40)(当-Xmx与-Xms相等时,该配置无效)
    • XX:MaxHeapFreeRatio=70:设置堆空间最大空闲比例(默认70)(当-Xmx与-Xms相等时,该配置无效)
    • XX:NewRatio=2:设置年轻代与年老代的比例为2:1
    • XX:SurvivorRatio=8:设置年轻代中eden区与survivor区的比例为8:1:1
    • XX:MetaspaceSize=64M:设置元数据空间初始大小(取代-XX:PermSize)
    • XX:MaxMetaspaceSize=128M:设置元数据空间最大值(取代之前-XX:MaxPermSize)
    • XX:TargetSurvivorRatio=50:设置survivor区使用率。当survivor区达到50%时,将对象送入老年代

    调优

    • 可以根据实际需要分配堆内存大小,运行程序,触发full GC,再根据实际情况调优
    • 如果条件足够,可以多分配点内存。可以适当调大Eden,让更少的临时对象进入Old区。
    • 可以考虑使用G1
    • 可以参考这篇博客,讲的比较详细。
    cs