JDK1.8 JVM调优之初识JVM(一)

作者:青山常在人不老   阅读 (1004)  |  收藏 (0)  |  点赞 (0)

摘要

本文将会带您走进JDK1.8的JVM调优的方法。


原文链接:JDK1.8 JVM调优之初识JVM(一)

在数据量和并发量极高的应用中,程序的健壮性和服务的稳定性一直是性能优化的一块重点区域,而GC则永远是程序中需要重点考虑的不稳定因素之一。
JVM调优大部分是调GC参数, GC参数主要关注三点:最大堆和最小堆大小;GC算法;新生代(年轻代)大小。
在JDK8及更早的版本, GC算法通常会在默认的Parallel和CMS中根据不同场合做选择, 新生代也要根据实际需求和自身经验手动调节大小才能达到性能和STW停顿的平衡.
而在JDK9及更新的版本中, 由于更为"智能"的G1成为默认,GC算法和新生代(年轻代)大小不用手动调节就能在大多数场合下达到几乎最优的性能, 通常只需配置最大堆容量和期望的STW暂停时间即可(不配置也可获得比较均衡合理的性能), 对技术能力和经验的要求大大降低了.
当然,我们需要明白的是:在没有全面监控、收集性能数据之前,调优就是瞎调。
本文为JDK 1.8下JVM调优系列文章的初识篇,主要普及基本的JVM组成和基本编译、运行原理。

JVM是Java Virtual Machine(Java虚拟机)的缩写,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
一个java类从.java到编译为.class再到通过JVM运行在windows和Linux机器上的流程如下:

file

大概解释下上面图中的流程:
我们在学Java的时候就知道一个基本常识:那就是Java语言是一次编译,多种平台上运行,也就是所说的跨平台。那么为什么Java能跨平台呢?专业的解释是Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行;通俗的解释是我们知道,一个文件在windows和Linux中会被解析成不同的二进制文件,那么其实我们的java文件在linux和windows上编译成class文件(字节码文件),它的机器码是不一样的,那么java是如何实现跨平台的呢?主要原因就是JVM内部针对不同的环境(windows、LinUx…)封装了不同的机器码处理程序(这就是为什么我们下载jdk时不同环境需要选择不同的jdk的最主要原因),当java被编译成class文件后,在不同的操作系统上,不同的JVM会将这个class文件转换成该操作系统所能处理的二进制,于是就实现了java所谓的一次编译、多地运行的目标。

class字节码文件是如何在JVM中运行的呢?
如下图,在运行class文件时候,JVM虚拟机首先会通过“类装在子系统”将.class文件加载到“运行时的数据区(也就是所说的内存模型)”中,最终由“字节码执行引擎”来一行行的运行“内存模型”中的代码。

file

我们知道JAVA虚拟机中最重要的就是运行时内存(内存模型),接下来我们就详细讲解“运行时数据区”的运行机制。

我们对“堆”的概念都不生疏,刚学JAVA时我们就应该知道New出来的对象都是放到“堆”里面。而且我们应该知道,JVM调优主要调的就是这块,堆放到后面讲。首先我们要讲下栈(线程栈)的概念

“栈”,官方称之为“虚拟机栈(Java Virtual Machine Stacks)”,咱们可以通俗的把它理解为“线程栈”(只要有一个线程在运行,java就会从内存模型中的栈中给它分配一个内存空间,用来放线程内部的局部变量)。“线程栈”的主要作用是为了承载线程运行过程中的局部变量。
例如如下代码:

public class Math
{
    public static final int initData  = 666;
    public static User      user      = new User();
    public int              initData1 = 666;

    public int compute()
    {
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
        return c;
    }

    public static void main(String[] args)
    {
        Math math = new Math();
        math.compute();
        System.out.println("test");
    }
}

当运行main方法时,JVM就会像下图一样给这个main线程分配一个栈:

file

当然,如果此时有第二个线程(线程2),那么JVM同样会给线程2创建一个栈。
当然,栈的内部其实很复杂,最直观的是栈内部有“栈帧”的概念。
所谓“栈帧”,指的就是当在当前线程中如果调用了其他方法(例如math.conpute()),此时就会在main线程的栈中再分出一块空间,用于存放该方法的局部变量(可以无限的创建内存统建),该被调用的方法结束,这这个内存空间消失,这就是栈帧。
如下图所示:

file

我们需要知道的是,栈的数据结构就是使用的数据结构中的栈(先进后出),之所以这样说,咱们可以参照上面的代码讲下:
首先在执行main方法时,JVM给main创建了一个内存空间(栈帧),然后在main方法中调用compute方法,此时,JVM给compute方法创建了一个内存空间(栈帧),当compute方法运行结束(局部变量销毁,栈帧销毁),继续执行main方法的sysout方法,然后main方法所在的栈帧销毁,遵循了先进后出的原则。

分类   Spring boot 开发
字数   2329

博客标签    JVM调优最新讲解   JDK 1.8性能调优  

评论