02-JVM内存模型深度剖析与优化

2023-10-27

一、JDK体系结构

在这里插入图片描述


JDK: JDK提供了编译、运行Java程序所需的各种资源和工具;包括Java编译器,Java运行时环境【JRE】;开发工具包括编译工具(javac.exe) 打包工具(jar.exe)等。
JRE: 即JAVA运行时环境,JVM就是包括在JRE中,以及常用的JAVA类库等;
SDK: SDK是基于JDK进行扩展的,是解决企业级开发的工具包。如JSP、JDBC、EJB等就是由SDK提供的 ;
JVM(Java Virtual Machine),Java虚拟机,可以看做是一台抽象化的计算机,它有一套完整的体系架构,包括处理器、堆栈 、寄存器等。
在运行时环境,JVM会将Java字节码解释成机器码。机器码和平台相关的(不同硬件环境、不同操作系统,产生的机器码不同),所以JVM在不同平台有不同的实现。
目前JDK默认使用的实现是Hotspot VM。

二、Java语言的跨平台特性

在这里插入图片描述


一次编译,到处执行(Write Once ,Run Anywhere)。
用Java创建的可执行二进制程序,能够不加改变的运行于多个平台。从软件层面屏蔽不同操作系统底层硬件与指令上的区别

三、JVM整体结构及内存模型

3.1 内存模型

官方文档参考:[https://doc](https://doc)s.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为个不同的数据区。这些区域有各自的用途,以及创建和销毁事件。
JVM用来存储加载的类信息、常量、静态变量、编译后的代码等数据。

在这里插入图片描述

PC寄存器(线程私有)

PC寄存器,也叫程序计数器。JVM支持多个线程同时运行,每个线程都有自己的程序计数器。倘若当前执行的是JVM方法,则该寄存器中保存当前执行指令的地址;倘若执行的是native方法,则PC寄存器为空。
这个内存区域是唯一一个在虚拟机中没有规定任何OutOfMemoryError情况的区域。

虚拟机栈(线程私有)

每个线程有一个私有的栈,随着线程的创建而创建。栈里面存放着一种叫做“栈帧”的东西,每个方法在执行的时候会创建一个栈帧,存储了局部变量表(基本数据类型和对象引用),操作数栈,动态连接,方法出口等信息。
每个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。
(方法中的局部变量的空间可以进行释放)
通常所说的栈,一般是指虚拟机栈中的局部变量表部分。局部变量表所需的内存在编译期间完成分配。
栈的大小可以固定也可以动态扩展,当扩展到无法申请足够的内存,则OutOfMemoryError。
当栈调用深度大于JVM所允许的范围,会抛出StackOverflowError的错误
演示栈帧:

public class StackTest {

    public int method2(){
        int a=1;
        int b=2;
        int c=a+b;
        return c;
    }

    public int method1(){
       return method2();
    }


    public static void main(String[] args) {
        StackTest stackTest = new StackTest();
        int i = stackTest.method1();
        System.out.println(i);
    }
}

本地方法栈(线程私有)

和虚拟机栈类似,主要为虚拟机使用到的Native方法服务。 也会抛出StackOverflowError和OutOfMemoryError。

堆(线程共享)

堆内存是JVM所有线程共享的部分,在虚拟机启动的时候就已经创建。
和程序开发密切相关,应用系统对象都保存在Java堆中。所有的对象和数组都在堆上进行分配。这部分空间可通过GC进行回收。对分代GC来说,堆也是分代的,是GC的主要工作区间。当申请不到空间时,会抛出OutOfMemoryError。
演示内存溢出:

public class HeapOutOfMemoryErrorTest {
    byte[] arr = new byte[1024 * 1000];//1M

    public static void main(String[] args) throws InterruptedException {
        ArrayList<HeapTest> list = new ArrayList<>();
        while (true) {
            list.add(new HeapTest());
        }
    }
}

结果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.zengqingfa.exercise.jvm.HeapTest.<init>(HeapTest.java:13)
	at com.zengqingfa.exercise.jvm.HeapOutOfMemoryErrorTest.main(HeapOutOfMemoryErrorTest.java:17)

方法区(线程共享)

方法区也是所有线程共享的。主要用于存储类的信息、常量池、方法数据、方法代码等。方法区逻辑上属于堆的一部分,但是为了与堆进行区分,通常又叫“非堆”。
这个区域的内存回收目标主要针对常量池的回收和对类型的卸载。
当方法区无法满足内存分配需求时,则抛出OutOfMemoryError异常。
在HotSpot虚拟机中,用永久代来实现方法区,将GC分代收集扩展至方法区,但是这样容易遇到内存溢出的问题。
JDK1.7中,已经把放在永久代的字符串常量池移到堆中。
JDK1.8撤销永久代,引入元空间。

运行时常量池

运行时常量池就是将编译后的类信息放入方法区中,也就是说它是方法区的一部分。** 运行时常量池用来动态获取类信息**,包括:class文件元信息描述、编译后的代码数据、引用类型数据、类文件常量池等。 运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中。

在这里插入图片描述

3.2 演示

堆内存回收

堆内存的回收过程,使用jvisualvm工具

public class HeapTest {

    byte[] arr = new byte[1024 * 100];//100kb

    public static void main(String[] args) throws InterruptedException {
        ArrayList<HeapTest> list = new ArrayList<>();
        while (true) {
            list.add(new HeapTest());
            Thread.sleep(10);
        }
    }
}

使用命令行:

jvisualvm

图形界面:

在这里插入图片描述


没有VisualGC界面,可以使用插件,下载即可,重启

在这里插入图片描述

启动程序,查看程序的运行过程:

在这里插入图片描述

四、jvm内存参数设值

在这里插入图片描述


Spring Boot程序的JVM参数设置格式(Tomcat启动直接加在bin目录下catalina.sh文件里):

java ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐jar eureka-server.jar

关于元空间的JVM参数有两个:-XX:MetaspaceSize=N和 -XX:MaxMetaspaceSize=N
-XX:MaxMetaspaceSize: 设置元空间最大值, 默认是-1, 即不限制, 或者说只受限于本地内存大小。
-XX:MetaspaceSize: 指定元空间触发Fullgc的初始阈值(元空间无固定初始大小), 以字节为单位,默认21M,达到该值就会触发full gc进行类型卸载, 同时收集器会对该值进行调整: 如果释放了大量的空间, 就适当降低该值; 如果释放了很少的空间, 那么在不超 过-XX:MaxMetaspaceSize(如果设置了的话) 的情况下, 适当提高该值。这个跟早期jdk版本的**-XX:PermSize**参数意思不一样,- XX:PermSize代表永久代的初始容量。
由于调整元空间的大小需要Full GC,这是非常昂贵的操作,如果应用在启动的时候发生大量Full GC,通常都是由于永久代或元空间发生 了大小调整,基于这种情况,一般建议在JVM参数中将MetaspaceSize和MaxMetaspaceSize设置成一样的值,并设置得比初始值要大, 对于8G物理内存的机器来说,一般我会将这两个值都设置为256M。

linux中jdk8 栈内存的默认大小:1M

[root@k8s-node02 ~]#  java -XX:+PrintFlagsFinal -version | grep ThreadStackSize
     intx CompilerThreadStackSize                  = 1024                                   {pd product} {default}
     intx ThreadStackSize                          = 1024                                   {pd product} {default}
     intx VMThreadStackSize                        = 1024                                   {pd product} {default}
openjdk version "11.0.10" 2021-01-19 LTS
OpenJDK Runtime Environment 18.9 (build 11.0.10+9-LTS)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.10+9-LTS, mixed mode, sharing)

演示栈内存溢出:

public class StackOverflowTest {

    //jvm设置 -Xss128k, -Xss默认1M     8倍   12548/8=1588
    static int count = 0;

    static void method() {
        count++;
        method();
    }

    public static void main(String[] args) {
        try {
            method();
        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println(count);

        }
    }
}

运行结果:

	java.lang.StackOverflowError
	at com.zengqingfa.exercise.jvm.StackOverflowTest.method(StackOverflowTest.java:15)
	at com.zengqingfa.exercise.jvm.StackOverflowTest.method(StackOverflowTest.java:16)
	at com.zengqingfa.exercise.jvm.StackOverflowTest.method(StackOverflowTest.java:16)
  at com.zengqingfa.exercise.jvm.StackOverflowTest.method(StackOverflowTest.java:16)
1098

**结论: -Xss设置越小count值越小,说明一个线程栈里能分配的栈帧就越少,但是对JVM整体来说能开启的线程数会更多 **
JVM内存参数大小该如何设置? JVM参数大小设置并没有固定标准,需要根据实际项目情况分析

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

02-JVM内存模型深度剖析与优化 的相关文章

  • 在 catch 块中重新抛出异常是否有意义?

    从 catch 块中抛出异常只是为了记录消息以便我们确定导致异常的原因是否有意义 Code public void saveLogs Logs logs throws RemoteException try LogsOps saveLogs
  • 在 JTable 中使用自定义 TablecellRenderer

    我是 Java 新手 我创建了一个JTable 就是这样addRow当我尝试向表中添加一行时 该方法有效 private void addTableRow String type String name String rank String
  • cygwin有java sdk吗?

    cygwin有java sdk吗 如果有一个使用 cygwin 文件系统和 X windows 进行显示的本机 cygwin 实现 那就太好了 不幸的是我不知道这样的版本 我认为移植 OpenJDK 也需要付出很大的努力 但我还没有尝试过
  • Java 8 中异常类型推断的一个独特功能

    在为该网站上的另一个答案编写代码时 我遇到了这个特性 static void testSneaky final Exception e new Exception sneakyThrow e no problems here nonSnea
  • Guice:当 FactoryBuilder 中提供合适的构造函数时,“找不到合适的构造函数”

    我使用 Guice 进行依赖注入 但收到此错误 1 Could not find a suitable constructor in java lang Void Classes must have either one and only
  • 视频文件转换/转码 Google App Engine

    我想启动一个云计算项目 其简单任务是 接收上传的视频文件 对它们进行一些转码 转换 允许用户下载 流式传输生成的文件 我刚在想ffmpeg作为集成在的外部命令行工具Java Google App engine Application 由于很
  • Java JNDI 名称 java:/

    我正在遵循教程 https docs oracle com javase tutorial jndi index html https docs oracle com javase tutorial jndi index html 我的冒险
  • LibGDX 闪烁

    我已经使用 LibGDX UI 设置来启动一个项目 我在实现 ApplicationListener 中唯一拥有的是 public void create setScreen new LoadingScreen this 这应该会触发 Lo
  • 枚举内的枚举

    这不是我被卡住的问题 而是我正在寻找一种简洁的方式来编写我的代码 本质上 我正在编写一个事件驱动的应用程序 用户触发事件 事件被发送到适当的对象 然后对象处理事件 现在我正在编写偶数处理程序方法 我希望使用 switch 语句来确定如何处理
  • Logback 配置在单行上有异常吗?

    我的日志被提取 传输并合并到 elasticsearch 中 多行事件很难跟踪和诊断 有没有办法使用收集器和正则表达式将异常行分组到单个记录中登录配置 https logback qos ch manual layouts html xTh
  • 声纳要求将这一领域定为最终目标

    我的程序中有以下代码 在与 Maven 集成后 我正在运行 SonarQube 5 对其进行代码质量检查 我面临这个错误 将此 public static processStatus 字段设为最终字段 将此 public static pr
  • MongoDb Spring 在嵌套对象中查找

    我正在使用 Spring Data Mongodb 和这样的文档 id ObjectId 565c5ed433a140520cdedd7f attributes 565c5ed433a140520cdedd73 333563851 list
  • 在仔细锁定但不受信任的代码上使用 Thread.stop()

    我知道Thread stop 已被弃用 并且有充分的理由 它通常不安全 但这并不意味着它是never安全 据我所知 在我想要使用它的上下文中它是安全的 而且 据我所知 我别无选择 上下文是一个两人策略游戏的第三方插件 以国际象棋为例 第三方
  • 使用mapstruct映射不同类型列表的元素

    我们正在映射一个对象 该对象具有一个对象列表 这些对象都实现了父接口 但可能具有不同的实现 但当我们映射列表时 似乎只有来自 ParentClass 的值被映射 而不是来自子类的值 但直接映射子进程就可以了 public class Par
  • 我的代码线程不安全吗?

    我编写了代码来理解 CyclicBarrier 我的应用程序模拟选举 每轮选出得票少的候选人 该候选人从竞争中淘汰以获得胜利 source class ElectoralCommission public volatile boolean
  • 使用 System.out.println 显示特殊字符

    我在将带有特殊字符的文本从网络服务发送或显示到数据库时遇到问题 在我的 Eclipse 上 我已将字符编码设置为 UTF 8 但它仍然不允许我显示字符 例如 像下面的代码一样简单的打印 String test System out prin
  • 如何在 VSCode 中热重载 Tomcat 服务器

    我正在从 Eclipse IDE VSCode 分别用于编码 Java servlet 和 HTML CSS JS 网页 迁移到仅使用 Visual Studio Code 因为它的轻量级 我为 VSCode 安装了几个 Java 扩展 R
  • 如何在 logback 中启动时滚动日志文件

    我想配置 logback 来执行以下操作 记录到文件 当文件达到 50MB 时滚动文件 仅保留 7 天的日志 启动时始终生成一个新文件 滚动 除了最后一项 启动卷 外 我一切都正常 有谁知道如何实现这一目标 这是配置
  • 旧的和奇异的 JVM 上 java.io.BufferedInputStream 的默认缓冲区大小是多少?

    我一直在为一篇关于以下内容的博客文章进行一些研究java io BufferedInputStream和缓冲区 显然 多年来 默认值已从区区 512 字节增长到 8192 字节 冒昧地 Sun 的 Java 7 实现 甚至在JDK 1 1
  • 将Json字符串映射到java中的map或hashmap字段

    假设我从服务器返回了以下 JSON 字符串 response imageInstances one id 1 url ONE two id 2 url TWO 杰克逊代码大厦 JsonProperty 我怎样才能得到HashMap对象出来了

随机推荐

  • angularJs摸态框实例加详细注解

  • mos 多路模拟电子开关_同步四开关 BuckBoost 180W 模块电源

    点击上方 21Dianyuan 关注我们 本文是 21Dianyuan 社区 原创 技术文章 作者 xueyiranpiao 感谢作者的辛苦付出 本电源主要应用于电池充电 电池为8串磷酸铁锂 10000mAH 0 6C 充电 也可以用于其它
  • Mybatis底层源码分析(最详细的版本)

    Mybatis底层源码分析 最详细的版本 1 概要介绍 MyBatis 是一款优秀的持久层框架 也是当前最流行的java持久层框架之一 它内部封装了jdbc 使开发 者只需要关注sql语句本身 而不需要花费精力去处理加载驱动 创建连接 创建
  • 网络编程知识预备(2) ——TCP三次握手与四次挥手、流量控制(滑动窗口)、拥塞控制、半连接状态、2MSL

    参考 浅显易懂的三次握手与四次挥手 作者 丶PURSUING 发布时间 2021 03 19 09 33 20 网址 https blog csdn net weixin 44742824 article details 114990198
  • python3 面向对象_Python3快速入门(六)——Python3面向对象

    Python3快速入门 六 Python3面向对象 一 面向对象技术简介 1 面向对象简介 面向对象编程 Object Oriented Programing OOP 是一种编程思想 OOP把对象当成程序的一个基本单元 一个对象包含数据和操
  • antd date-picker 默认时间设置问题

    一 官网给出的例子
  • Python编程:通讯录(文件读取)

    描述 读取附件中的csv文件 通讯录信息 放入字典中 后两项以列表形式做为字典的值 并依次输出其中的信息 文件内数据不需要修改 输出时数据之间以空格间隔 编码格式使用GBK 输入 A 时 按行输出文件信息 输入 D 时 直接输出字典内容 输
  • vue3 props属性基本使用梳理

    前言 vue2中props属性的使用是比较统一的基本就一种方式 但是vue3中其实方式是比较多的 因此就打算梳理一下 会按照选项式和组合式进行梳理 包括属性的定义 取值以及属性的监听 应该是叫单文件组件和组合式API 不知道vue官方是根据
  • 递归->栈->队列面试题

    本文所有程序均已测试通过 测试结果图就不一个一个再截图了 读者可以自己copy验证一下 后期我会把思路图补出来 1 行走机器人问题 货架N个 机器人初始位置在pos 经过minutes分钟后到达T有多少种方案 行走机器人问题 货架N个 机器
  • 使用Hexo从0到1搭建个人博客详细教程(超详细,超简单)

    看完这篇 轻轻松松搭建个人博客 校花 班花 额 额 看了就会的博客搭建教程 一 搭建前的软件准备 git node 二 安装hexo 完成简单本地页面展示 三 将Hexo部署到Github 1 Github创建个人仓库 2 生成ssh添加到
  • WebStorm功能特点以及使用指南

    WebStorm功能特点以及使用指南 首先看看WebStorm合其他的IDE有什么特别之处 1 自动保存 不需要你一次又一次地ctrl s啦 所有的操作都直接存储 当然 万一键盘误操作也会被立即存储 不过我们可以通过本地版本控制解决这个问题
  • 创建型模式-建造者模式理解

    1 前言 首先建造者模式适合下面的场景 进行使用 假设不同的对象有着基本的共同特点 或者配合前端进行页面布局 进行构建一个复杂的对象 那么可以参考工厂方法模式进行抽取对象 并进行解耦 达到一个设计符合要求的对象的过程 eg 1 保险产品 前
  • python自适应图片大小_python – 如何在Pygame中将图像缩放到屏幕尺寸

    您可以使用pygame transform scale缩放图像 import pygame picture pygame image load filename picture pygame transform scale picture
  • 小世界网络和复杂网络+python代码实现

    文章目录 小世界网络 复杂网络的特性 平均路径长度L 聚集系数C 度及度分布 小世界效应 规则网络 随机网络 小世界网络 无标度网络 python 代码 生成小世界网络 规则网络 喜欢的话请关注我们的微信公众号 你好世界炼丹师 公众号主要讲
  • 头文件重复定义问题解决“C1014错误“

    比如现在有三个文件 两个头文件 一个 cpp文件 header1 h include header2 h int fun2 header2 h include header1 h int fun main cpp include heade
  • Git学习笔记----基础运用

    安装Git Windows 进入官网下载或百度网盘下载 Git V2 23 x64 提取码 uf2x Ubuntu sudo apt get install git 安装完成之后打开git命令行 Ubuntu命令行即可操作 输入以下代码 查
  • Linux内核设计与实现 第六章 内核数据结构

    目录 1 单向链表和双向链表 编辑 编辑 2 环形链表 3 沿链表移动 4 Linux内核中的实现 5 操作链表 6 遍历链表 6 2队列 1 kfifo 2 创建队列 3 推入队列数据 4 摘取队列数据 5 获取队列数据 6 重置和撤销队
  • hook控制浏览器的方法_一个用于监听 dom 节点尺寸变化的 Hook

    平时写项目应该经常会遇见表格动态高度适应不同屏幕和浏览器调整窗口大小的问题 一般解决办法就是使用 resize 事件来监听窗口改变 如果我要监听 textarea 的大小来做些效果 resize 事件就没办法了 因为它不能监听 DOM 的改
  • flex 初学

    flex direction 主轴的排列方向 box flex direction row row reverse column column reverse justify content 项目在主轴上的对其方式 box justify
  • 02-JVM内存模型深度剖析与优化

    一 JDK体系结构 JDK JDK提供了编译 运行Java程序所需的各种资源和工具 包括Java编译器 Java运行时环境 JRE 开发工具包括编译工具 javac exe 打包工具 jar exe 等 JRE 即JAVA运行时环境 JVM