前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Java虚拟机】JVM核心基础和常见参数实战

【Java虚拟机】JVM核心基础和常见参数实战

原创
作者头像
互联网小阿祥
发布2023-05-28 21:52:35
5380
发布2023-05-28 21:52:35
举报

@TOC

1.新版JVM内存组成部分和堆空间分布

JVM内存的5大组成(基于JDK8的HotSpot虚拟机,不同虚拟机不同版本会有不一样)

名称

作用

特点

程序计数器

也叫PC寄存器,用于记录当前线程执行的字节码指令位置,以便线程在恢复执行时能够从正确的位置开始

线程私有

Java虚拟机栈

用于存储Java方法执行过程中的局部变量、方法参数和返回值,以及方法执行时的操作数栈

线程私有

本地方法栈

用于存储Java程序调用本地方法的参数和返回值等信息。

线程私有

用于存储Java程序创建的对象,所有线程共享一个堆,堆中的对象可以被垃圾回收器回收,以便为新的对象分配空间

线程共享

元数据区

用于存储类的元数据信息,如类名、方法名、字段名等,以及动态生成的代理类、动态生成的字节码等 元空间是位于本地(直接)内存中的,而不是像JDK8之前方法区位于堆内存中的。

线程共享

在这里插入图片描述
在这里插入图片描述

堆空间内存分布

  • 用于存储Java程序创建的对象,所有线程共享一个堆
  • 堆中的对象可以被垃圾回收器回收,以便为新的对象分配空间
在这里插入图片描述
在这里插入图片描述
2.JVM堆空间垃圾回收流程

(1)面试题:说下JVM里面堆内存划分和堆内存垃圾回收流程

  • 新建对象,放到Eden区,满后触发Minor GC(每次都是由Eden区满触发Minor GC,接连放对象到S0或S1)
  • 存活的对象移动到Survivor的S0区,如果S0满后触发Minor GC
  • S0存活下来的对象移动到S1区,然后S0区空闲
  • S1满后触发Minor GC,再次移动到S0区,然后S1区空闲
  • 反复GC每次对象涨1岁,到达一定次数后(默认15),进入老年代
  • 当老年代内存不足会触发Full GC,出现STW(Stop-The-World)
  • 堆被垃圾回收,基本都是采用分代收集算法,不通区域的采用不同的垃圾回收算法
  • 方法结束后,堆中的对象不会马上移除,在垃圾回收的时候才会被移除

(2)面试题:堆空间里面分配比例如何

在这里插入图片描述
在这里插入图片描述

官方推荐一般老年代与新生代的占比为2:1,即老年代占整个堆空间的2/3,新生代占整个堆空间的1/3,在Yong区又分三个区域 Eden、Survivor-0、Survivor-1,Eden分整个Yong的8/10,两个Survivor各占1/10。

3.JVM内存垃圾回收相关参数

(1)JVM参数格式分类

格式

解释

例子

标准参数(-)

所有JVM都实现这些参数的功能

-verbose:gc 打印GC简要信息

非标准参数(-X)

不保证所有JVM实现都满足

-Xmx2048m等价 -XX:MaxHeapSize JVM最大堆内存为2048M

非稳定参数(-XX)

不稳定未来可能取消,但很有用

-XX:+PrintGCDetails每次GC时打印详细信息。

-XX:+

开启对应的参数

-XX:+PrintGCDetails 开启每次GC时打印详细信息。

-XX:-

关闭对应的参数

-XX:-DisableExplicitGC 禁止调用System.gc()

-XX:=

设定数字参数

-XX:NewRatio=2 新生代和老年代内存比例

(2)JVM堆栈内存配置参数

参数

解释

-Xms

初始堆大小,推荐和最大堆一样

-Xmx

最大堆大小,推荐和初始堆一样

-Xmn

年轻代大小

-Xss

每个线程的栈大小

(3)JVM常见的命令行参数配置

参数

解释

-XX:+PrintGCDetails

打印GC回收信息

-XX:NewRatio

新生代和老年代空间大小的比率,由-XX:NewRatio参数控制 -XX:NewRatio参数的默认值是2,表示新生代和老年代的比例是1:2 如果将-XX:NewRatio设置为4,表示新生代和老年代的比例是1:4

-XX:MaxMetaspaceSize

元空间所分配内存的最大值,默认没限制

-XX:+UseConcMarkSweepGC

设置并发收集器

4.JVM虚拟机栈参数调整案例实战

JVM虚拟机栈

  • 用来存储Java程序中的方法调用和局部变量的内存区域
  • 每个线程都有自己的虚拟机栈,其生命周期与线程相同
  • 当一个方法被调用时,Java虚拟机会在该线程的虚拟机栈中创建一个栈帧,用来存储该方法的局部变量、方法返回值等信息
  • 异常情况
    • 默认情况下,JVM虚拟机栈的大小是固定的,JDK1.5后通常为1MB
    • 如果线程在执行方法时需要更多的栈空间,JVM会抛出StackOverflowError异常
    • JVM参数 xss,比如 -Xss1m 表示1MB

(1)案例:模拟递归调用,对count一直++,直到栈溢出

代码语言:java
复制
public class StackFrameDemo {

    private static int count = 0;
    
    public static void main(String[] args) {
        try {
            recursiveMethod();
        } catch (Throwable t) {
            System.out.println("Stack overflow after " + count + " invocations.");
            t.printStackTrace();
        }
    }

    private static void recursiveMethod() {
        count++;
        recursiveMethod();
    }

}
  • 配置栈大小,最少208k,低于208k启动不起来项目,我们这块配置 524k,-Xss524k
在这里插入图片描述
在这里插入图片描述
  • 再次测试
在这里插入图片描述
在这里插入图片描述
  • 结论:
  • 栈越小,递归调用的次数就越少,因为栈空间不足导致栈溢出异常
  • 栈越大,递归调用的次数就越多,因为有足够的栈空间来存储方法调用的信息
5.JVM堆参数调整压测案例实战
  • 需求
    • 通过调整不同的JVM堆参数,查看相关指标
  • 测试接口
代码语言:java
复制
@RestController
@RequestMapping("api/v1/data")
public class DataController {

    @RequestMapping("compute")
    public String compute() {
        Byte[] b = new Byte[1024*1024];
        return "success";
    }
}
  • JVM参数
  • 调整参数一
  • 参数 -Xms64m -Xmx64m
  • 性能指标
在这里插入图片描述
在这里插入图片描述
  • 调整参数二
  • 参数 -Xms640m -Xmx640m
  • 性能指标
在这里插入图片描述
在这里插入图片描述
6.JDK8之后的方法区实现和元空间的联系

(1)什么是方法区和元空间

  • 【方法区】是JVM中用来存储类的元数据信息的区域,包括类的结构、方法、字段信息等,Java堆类似各个线程共享的内存区域
  • 元空间、永久代是方法区具体的落地实现
    • java8之前是称为永久代(PermGen),java8后引入的一个新概念【元空间】用于替代旧版JVM中的永久代(PermGen)
代码语言:txt
复制
* 方法区和永久代以及元空间的关系很像 Java 中接口和类的关系
* 类实现了接口,类就可以看作是永久代和元空间,接口可以看作是方法区
* 永久代是 JDK 1.8 之前的方法区实现,JDK 1.8 及以后方法区的实现便成为元空间
在这里插入图片描述
在这里插入图片描述
  • 元空间的大小是动态的,可以根据需要进行自动扩展,如果元空间不足,JVM会抛出 OutOfMemoryError : Metaspace
  • 元空间大小配置
  • -XX:MetaspaceSize
    • 用来设置元空间初始大小的参数,它的默认值是21 MB
  • -XX:MaxMetaspaceSize
    • 用来设置元空间最大大小的参数,它的默认值是-1 即不限制,使用的是本地内存,不像旧版的永久代是堆内存
    • 如果不限制元空间的大小,可能会导致元空间占用过多的内存,从而引起内存溢出
  • 系统参数查看
代码语言:txt
复制
* 这两个参数的单位是字节(B),可以使用K、M、G等后缀来表示更大的单位
代码语言:java
复制
public class HeapDemo {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("测试元空间进程");
        Thread.sleep(10000000);
    }
}
  • 查看命令
代码语言:shell
复制
jps #查看进程号
jinfo -flag MetaspaceSize 进程号  #查看Metaspace分配内存空间 
jinfo -flag MaxMetaspaceSize 进程号 #查看Metaspace最大空间
在这里插入图片描述
在这里插入图片描述
  • 调整
代码语言:java
复制
-XX:MetaspaceSize=126m -XX:MaxMetaspaceSize=524m
在这里插入图片描述
在这里插入图片描述

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.新版JVM内存组成部分和堆空间分布
  • 2.JVM堆空间垃圾回收流程
  • 3.JVM内存垃圾回收相关参数
  • 4.JVM虚拟机栈参数调整案例实战
  • 5.JVM堆参数调整压测案例实战
  • 6.JDK8之后的方法区实现和元空间的联系
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com