JVM内存模型深度解读

这篇具有很好参考价值的文章主要介绍了JVM内存模型深度解读。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        JVM(Java Virtual Machine,Java虚拟机)对于Java开发者和运行 Java 应用程序而言至关重要。其重要性主要体现在跨平台性、内存管理和垃圾回收、性能优化、安全性和稳定性、故障排查与性能调优等方面。今天就下学习一下 JVM 的内存模型。

一、JVM内存模型

        JVM 内存模型(Java Virtual Machine Memory Model,简称JMM)是 Java 虚拟机规范定义的一种内存结构组织方式,用于规定 Java 程序在 JVM 中的运行时数据区域划分以及它们之间的关系。它不仅描述了如何划分内存区域,还规定了线程如何访问这些内存区域以及线程间的通信规则。JMM 如下图:JVM内存模型深度解读,Java基础,jvm,JVM内存模型,Java

        JVM内存模型主要分为程序计数器、Java虚拟机栈、本地方法栈、堆、方法区、运行时常量池、直接内存,下面来分别看下。

二、程序计数器

         程序计数器(Program counter Register)是一块较小的内存空间,它可以看做是当前线程所执行字节码的指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条要执行的字节码指令,它是程序流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要这个计数器来完成。每条线程独立拥有程序计数器,各线程之间计数器互不影响。

        如果线程正在执行 java 方法,这个计数器记录的是正在执行的虚拟机字节码指令地址;如果正在执行的是本地(native)方法,这个计数器值则应为空。程序计数器是唯一一个在《Java虚拟机规范》中没有规定任何 OutOfMemeryError 情况的区域。

 三、 java虚拟机

        与程序计数器一样,java 虚拟机栈也是线程私有的,他的生命周期与线程一样。虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,java虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法的出口等信息。每一个方法在虚拟机栈中的执行完毕过程,就对应这一个栈帧从入栈到出栈的过程。

        局部变量表存放了编译期可知的各种Java虚拟机基本数据类型(byte、short、char、int 、float、double、long、boolean)、对象引用(refrence类型,它并不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象句柄或者其他与此对象相关的位置)和returnAddress类型。

        下面看一个例子

public class Test {

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

    public static void main(String[] args) {
        int cacl = cacl();
        System.out.println(cacl);
    }

}

JVM内存模型深度解读,Java基础,jvm,JVM内存模型,Java

        局部变量表是一组变量值的存储空间,用于存放方法参数和方法内部定义的局部变量。

        操作数栈是一个先进后出的栈,当一个方法刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种各样的字节码指令往操作数栈中写入和提取,也就是出栈和入栈。

        动态链接,每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接。Class文件中的常量池存有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数。

四、 本地方法栈

        本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用非常相似,其区别只是虚拟机栈为虚拟机执行 java 方法服务,而本地方法栈则是为虚拟机使用本地方法服务。

五、 堆

        Java 堆(Java Heap)是虚拟机所管理的内存最大的一块。java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,此内存区域的唯一目的是存放对象实例。JVM内存模型深度解读,Java基础,jvm,JVM内存模型,Java

        new 出来的对象是放到了 Eden 区,老年代默认占整个堆的 2/3 空间。JVM的分代理论中什么条件下会从新生代晋升到老年代?

  1. 默认情况下,对象经历了15次 minor gc,年龄变为15就会变为老年代。
  2. 假如说当前放对象的Survivor 区域里一批对象的总大小大于了这块 Survivor 区域的内存大小的50% ,那么此时大于等于这批对象年龄的对象,就可以直接进入老年代了。
  3. 一些大对象在创建是也会放到老年代。老年代的包括一些链接,比如连接池等。

六、 方法区

        方法区(Method Area)与 java 堆一样是线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态常量、及时编译器编译后的代码缓存等数据。方法区是JVM的一个逻辑部分,具体实现在java7之前时永久代,Java8之后是元空间。

        那元空间和永久代有什么区别呢?

        JDK8 及以后把类的元数据放在本地内存中,这一块区域叫做 Metaspace,该区域在 jdk7 及以前是属于永久代的,元空间和永久代都是用来存储 class 相关信息,包括 class 对象的method、field 等。元空间和永久代其实都是方法区的实现,只是实现不同,所以说方法区只是JVM的规范。

        当前的主流框架,如 spring 等对类进行增强时都会使用 CgLib 等字节码技术,当增强的类越多,就需要越大的方法区,以保证动态生成的新类能载入内存。经常在运行时生成大量动态类的应用场景,应特别注意这些类的回收情况。

        在 java7 之后,原先位于方法区里的字符串常量池也被移到了堆中。并在 Java8 中使用元空间代替了永久代。这一替代最大的区别是元空间使用的是本地内存,而永久代使用的是 jvm 内存,使用本地内存的好处是J ava.lang.outofMemoryError:PermGen Space 将不复存在,只受限于本地内存大小的限制,解决了空间不足的问题,不过也不可能任其无限大,jvm在默认运行时会根据需要动态的设置其大小,这一替换的好处如下:

  • 字符串常量池在永久代中容易出现性能问题和内存溢出问题。
  • 类的方法信息大小难以确定,因此给永久代的大小指定带来了困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。永久代会为 GC 带来不必要的复杂性,并且回收效率偏低,在永久代中元数据可能会随着每一次 full gc 发生而进行移动,而 hotspot 虚拟机每种类型的垃圾回收器都要特殊处理永久代中的元数据,分离出来后可以简化 full gc。

        如下为永久代合堆的存储位置

JVM内存模型深度解读,Java基础,jvm,JVM内存模型,Java

七、 运行时常量池

        运行时常量池(Runtime Constant Pool)是方法区的一部分。class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项常量池,用于存放编译器生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池。

        运行期间也可以将新的常量放入池中,比如String的intern()方法

八、 直接内存

        直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是《java虚拟机规范》中定义的内存区域。但是这部分内存也被频繁的使用,而且也可能导致OutOfMemoryError异常的出现。

        在 JDK1.4 中新加入的 NIO 类,引入了一种基于通道(channel)与缓存区(Buffer)的 I/O方式,它可以使用 Native 函数库直接分配内存,然后通过一个存储在 Java 堆里面的DirecByBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提升性能,因为避免了在 java 堆和 native 堆中来回复制数据。

        显然,本地直接内存分配不受 java 堆大小的限制,但是既然是内存,则肯定还是会受到本机总内存大小及处理器寻址空间的限制。

        因为通常的垃圾收集日志等记录,并不包含 Direct Buffer 等信息,所以 Direct Buffer 内存诊断也是个比较头疼的事情,在JDK 8 之后的版本,可以方便的使用 Native Memory Tracking(NMT) 特性来诊断,可以在程序启动时增加下面的参数:

-XX:NativeMemoryTracking={summary|detail}

        注意,激活NMT通常会导致JVM 5%~10%的性能下降,需要慎重使用。

        总结:了解了JVM的内存模型后才能更好的理解对象创建、垃圾回收等等功能,后续将继续介绍这部分内容。

往期经典推荐

实时数据传输的新里程——Server-Sent Events(SSE)消息推送技术-CSDN博客

SpringBoot项目并发处理大揭秘,你知道它到底能应对多少请求洪峰?_springboot并发处理-CSDN博客

领航分布式消息系统:一起探索Apache Kafka的核心术语及其应用场景-CSDN博客

Redis性能大挑战:深入剖析缓存抖动现象及有效应对的战术指南_redis 缓存抖动怎么解决-CSDN博客

MySQL中order by原来是这么工作的-CSDN博客文章来源地址https://www.toymoban.com/news/detail-841465.html

到了这里,关于JVM内存模型深度解读的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • jvm 程序计算器 程序计数器是否溢出 程序计数器是做什么的 java程序计数器会内存溢出吗 程序计数器作用与用处 jvm内存模型 jvm合集(一)

    1. jvm内存模型:     内存模型:                     程序计数器                     堆                     栈                     本地方法栈                     方法区 2. java代码编译为class文件,由类加载器加载到jvm,然后

    2024年02月09日
    浏览(48)
  • JVM零基础到高级实战之Java内存区域本地方法栈

    JVM零基础到高级实战之Java内存区域本地方法栈 JVM零基础到高级实战之Java内存区域本地方法栈 本地方法栈是什么? 用于作用域本地方法执行的一块Java内存区域 为什么要有本地方法栈? 与Java虚拟机栈相同,每个方法在执行的同时都会创建一个栈帧(Stack Framel)用于存储局部

    2024年02月09日
    浏览(42)
  • 【JVM】JVM内存模型详解

    一、JVM是什么? JVM是Java Virtual Machine(Java虚拟机)的缩写,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成。JVM屏蔽了与操作系统平台相关的信息,使得Java程序只需要生成在

    2024年02月14日
    浏览(47)
  • 【JVM】JVM内存模型(详细)

    JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 Java中的所有类,必须被装载到JVM中才能运行,这个装载工作是由jvm中的类装载器完成的,.class这个类型可以

    2023年04月08日
    浏览(34)
  • JVM前世今生之JVM内存模型

    JVM内存模型所指的是JVM运行时区域,该区域分为两大块 线程共享区域 堆内存、方法区,即所有线程都能访问该区域,随着虚拟机和GC创建和销毁 线程独占区域 虚拟机栈、本地方法栈、程序计数器,即每个线程都有自己独立的区域,该区域随着线程的生命周期创建和销毁  

    2024年02月12日
    浏览(35)
  • 06-JVM对象内存回收机制深度剖析

    上一篇:05-JVM内存分配机制深度剖析 堆中几乎放着所有的对象实例,对堆垃圾回收前的第一步就是要判断哪些对象已经死亡( 即不能再被任何途径使用的对象 )。 给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加1;当引用失效,计数器就减1;任何时候计

    2024年02月09日
    浏览(45)
  • JVM原理:JVM运行时内存模型(通俗易懂)

    做了几年开发,平时除了写代码造BUG和修复BUG之外,偶尔也会遇到反馈说程序较慢问题,要对程序性能排查与优化就得更深入学习,学习JVM可以帮助我们加深对JAVA的理解,让我们具备一定的性能排查与调优的能力,无非就是让程序别太卡或者别挂了,那挂了目前我遇到的主要

    2024年02月08日
    浏览(55)
  • JVM对象创建与内存分配机制深度剖析

    (1)类加载检查 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程; 所以所类加载是 懒加载 ; new指令对应到语

    2024年02月13日
    浏览(49)
  • JVM内存模型详解

    JVM内存模型和Java内存模型都是面试的热点问题,名字看感觉都差不多,实际上他们之间差别还是挺大的。     通俗点说,JVM内存结构是与JVM的内部存储结构相关,而Java内存模型是与多线程编程相关@mikechen。   什么是JVM JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一个虚

    2023年04月13日
    浏览(60)
  • JVM oop内存模型

    1、非数组对象 InstaceOopDesc 2、数组对象  arrayOopDesc         2.1 基本数据类型数组 typeArrayOopDesc         2.2 引用类型数组 objArrayOopDesc  3、MarkOopDesc         存放锁信息、分代年龄等 1、InstanceKlass是JVM中表示类的对象的数据结构。JVM在加载class时,会创建 instanceKlass ,表示其元

    2024年02月12日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包