当前位置:首页 > Java技术 > JVM内存模型详解

JVM内存模型详解

2022年11月07日 20:29:46Java技术6

内存模型

内存模型如下图所示

JVM内存模型详解 _ JavaClub全栈架构师技术笔记

堆是Java虚拟机所管理的内存最大一块。堆是所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域唯一的目的就是存放对象实例。所有的对象实例都在这里分配内存

Java堆是垃圾收集器管理的主要区域。从内存回收的角度来看,由于现在的垃圾收集器采用的是分代收集算法。所以,java堆又分为新生代老年代。从内存分配的角度来说,线程共享的java对中可能划分出多个线程私有的fenp缓冲区(Thread Local Allocation Buffer)。

可以通过 -Xms-Xmx分别控制堆初始化是最小堆内存和最大堆内存大小。

虚拟机栈

与程序计数器一样,java虚拟机栈也是线程私有的,他的生命周期与线程相同

虚拟机栈描述的是Java方法的执行的内存模型:每个方法在执行的同时会创建一个栈桢(stack frame)用于存储局部变量表、操作数栈、动态链表、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着栈桢在虚拟机栈中入栈到出栈的过程。

虚拟机栈存储的数据类型
  • 局部变量表

    存放的是编译器可知得到各种基本数据类型boolean、byte、char、short、int、float、long、double、对象引用(refrence类型,不等同于对象本身,一个指向对象的起始内存位置的引用指针)
  • 操作数栈
  • 动态链表
  • 方法出口
  • ...
常见异常

在虚拟机规范中,对这个区域规定了两种异常情况:

  1. 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError
  2. 如果虚拟机栈可以动态扩展,扩展时无法申请做够的内存,将会爬出OutOfMemorryError

本地方法栈

与虚拟机栈发挥的作用非常类似,他们之间的区别是虚拟机栈为虚拟机执行java方法服务,而本地方法栈则为虚拟机使用到的native方法服务。与虚拟机栈一样,本地房发展区域也会抛出StackOverflowErrorOutOfMemorryError异常。

方法区(1.8后该区域被废弃)

方法区与java堆一样,是各个线程所共享的,它用来存储已被虚拟机加载的类信息常量静态变量即时编译后的代码等数据

方法区是jvm提出的规范,而永久代就是方法区的具体实现。

java虚拟机对方法区的限制非常宽松,可以像堆一样不需要连续的内存可可选择的固定大小外,还可以选择不识闲垃圾收集,相对而言,垃圾收集行为在这边区域是比较少出现的。

在方法区会报出 永久代内存溢出的错误。而java1.8为了解决这个问题,就提出了meta space(元空间)的概念,就是为了解决永久代内存溢出的情况,一般来说,在不指定 meta space大小的情况下,虚拟机方法区内存大小就是宿主主机的内存大小

程序计数器

程序计数器是一块较小的内存空间,他可以看做是当前线程所执行字节码的行号指示器。在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选择下一条将要执行的字节码指令。

由于JAVA虚拟机的多线程是通过多线程流转切换并分配处理器执行时间的方式来实现的。在任一一个确定的时刻,一个处理器都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,各个线程的计数器之间互不影响,独立存储,我们称该类内存区域为线程私有

如果线程正在执行一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址。

运行时常量池

运行时常量池是方法区的一部分。Class文件除了 有类的版本、字段、方法、接口等描述信息外,还有一项是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容在类加载后进入方法区的运行时常量池。

运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性.Java语言并不要求常量一定只有在编译器才能产生,依旧是并非预置入Class文件中的常量池的内容才能进入方法区运行时常量池

对象创建

在语言层面上,创建对象(克隆,反序列化)通常只是一个new关键字。

过程

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

在类加载检查通过后,接下来虚拟机将为新生的对象分配内存。对象所需内存的大小在类加载完成后便可完全确定。

内存分配

为对象分配空间的任务等同于把一块确定大小的内存从java堆中划分出来。假设java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的放在另外一边,中间放着一个指针最为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲的空间那边挪动一段与对象大小相等的距离,这种分配方式称为指针碰撞

如果内存不是规整的,已使用的和空闲的内存区域是相互交错的,虚拟机必须维护一个列表,记录哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新这个列表。这种分配方式是空闲列表

选择哪种分配分配方式是由java堆是否规整来决定的,而java堆是否规整又是由其所采用 的垃圾收集器是否带有压缩规整的功能决定,因此,使用SerialParNew等带来Compat过程的收集器时,分配算法是指针碰撞。而使用CMS这种基于Mark-Swaeep算法,采用的是空闲列表分配方式。

对象的内存布局

在HotSpot虚拟机中,对象在内存中的存储布局分为3块区域:对象头(Header)实例数据(Instance Data)对其补充(Padding)

对象头(Heading)

对象头包括两部分信息

  1. 用于存储对象自身运行时数据。

如哈希码,GC分代年龄、锁状态标志、偏向线程ID。这部分s数据的长度在32位和64位的虚拟机中分别为32bit和64bit。

对象的访问定位

创建对象时为了使用对象,java程序需要通过栈上的refrence数据来操作堆上的具体对象。由于refrence类在java虚拟机值规定了一个指向对象的引用,并没有定义这个引用应该通过何种方式去定位、访问堆中的具体位置,所以对象访问方式也取决于虚拟机对这个refrence的具体实现,目前主流的访问凡是是使用句柄直接指针两种。

句柄访问

如果使用句柄访问的话,那么java堆中就会划分出一块内存来座位句柄池,refrence中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据的各自具体的地址信息。

JVM内存模型详解 _ JavaClub全栈架构师技术笔记

指针直接访问

如果使用指针直接访问,那么java堆对象的布局就必须考虑如何放置访问类型数据的相关信息,而refrence中存储的直接就是对象地址

JVM内存模型详解 _ JavaClub全栈架构师技术笔记
这个两种访问方式各有优势,使用句柄访问的最大好处就是refrence中存储的是稳定的句柄地址,在对象被移动(垃圾收集时)只会改变句柄中对象实例指针,refrence本省不需要修改。

使用直接指针访问的方式最大的好处就是速度更快,节省了一次指针定位的事件开销。由于对象的访问在java中非常频繁,一次这类开销积少成多也是一个比较客观的优化。

作者:Ronaldo7
来源链接:https://www.cnblogs.com/KevinStark/p/10925666.html

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/68426.html

分享给朋友:

“JVM内存模型详解” 的相关文章

IDEA启动失败,报Failed to create JVM错误的解决办法

IDEA启动失败,报Failed to create JVM错误的解决办法

IDEA启动失败,报Failed to create JVM错误的解决办法 从网上下载的破解版IDEA,照网上的pojie方法进行破解时,很多人是用Windows自带的记事本添加并保存的。但是用记事本保存的文件是带有BOM的,从而导致启动IDEA报...

深入理解JVM—JVM内存模型

深入理解JVM—JVM内存模型

原文地址:http://yhjhappy234.blog.163.com/blog/static/316328322011101723933875/?suggestedreading&wumii 我们知道,计算机CPU和内存的交互是最频繁的,内存是我们的高速缓存区,用户磁...

java jvm设置

2. 如何分配JVM内存设置: (1)当在命令提示符下启动并使用JVM时(只对当前运行的类Test生效):     java -Xmx128m -Xms64m -Xmn32m -Xss16m Test     (2)当在集...

jvisualVm监控远程的jvm

jvisualVm监控远程的jvm

jvisualVm是Netbeans的profile子项目,已在JDK6.0 update 7 中自带(java启动时不需要特定参数,监控工具在bin/jvisualvm.exe),能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的...

JVM原理

JVM原理

注明:转载文章。 一、什么是JVM     JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。...

JVM——Java内存模型(JMM)

JVM——Java内存模型(JMM)

本文主要介绍JVM——Java内存模型(JMM),并介绍原子性、可见性、有序性以及先行发生原则。 软硬件发展概述 Amdahl定律和摩尔定律 1)Amdahl定律:通过系统中并行化和串行化的比重来描述多处理器系统能获得的运算加速能力。 2)摩尔定律:用于描...

一、JVM运行原理之Java内存模型

一、JVM运行原理之Java内存模型

JVM内存模型   对于Java开发者来说,我们不必关注内存的使用和释放问题,而是统一的交由Java虚拟机去统一的管理,这样一方面大大减轻了开发者的负担,同时也降低的开发的门槛,所以现在Java的广泛使用,Java虚拟机功不可没。虽然我们在开发过程中不必关注虚拟机的运行状况,但如...

线上jvm 内存飙高排查

线上jvm 内存飙高排查

1.jps查看java进程的pid 2.使用jmap把内存导出,查看是哪些对象占用内存高 jmap -histo 16352 >f:/dev/histo.txt 3. 使用jmap查看堆内存的使用情况 jmap -heap 16...

jvm系列五-java内存模型(2)

jvm系列五-java内存模型(2)

原作者系列文章链接:并发编程系列博客传送门 前言# 在网上看了很多文章,也看了好几本书中关于JMM的介绍,我发现JMM确实是Java中比较难以理解的概念。网上很多文章中关于JMM的介绍要么是照搬了一些书上的内容,要么就干脆介绍的就是错的。本文试着用比较简洁的...

jvm(一)

jvm(一)

JVM与Java体系结构 前言 作为Java工程师的你曾被伤害过吗?你是否也遇到过这些问题? 运行着的线上系统突然卡死,系统无法访问,甚至直接OOMM! 想解决线上JVM GC问题,但却无从下手。 新项目上线,对各种...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。