用几张图深度剖析Java内存模型

简介: 首先看一张图:下图是Java虚拟机运行时数据区,JVM的内存模型可以分为方法区、虚拟机栈、本地方法栈、堆和程序计数器。

网络异常,图片无法展示
|


听说微信搜索《Java鱼仔》会变更强哦!


本文收录于githubgitee ,里面有我完整的Java系列文章,学习或面试都可以看看哦


(一)基础概念介绍


首先看一张图:下图是Java虚拟机运行时数据区,JVM的内存模型可以分为方法区、虚拟机栈、本地方法栈、堆和程序计数器。


网络异常,图片无法展示
|


首先还是介绍一下基本概念


程序计数器


程序计数器的作用可以看成是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变计数器的值来选择下一条需要执行的字节码的指令。java虚拟机的多线程是通过线程轮流切换来分配处理器执行时间的方式实现的,为了线程切换之后能恢复到正确的执行位置,每个线程就需要一个独立的程序计数器。


java虚拟机栈: java虚拟机栈线程私有,每个方法被执行的同时都会创建一个栈帧用于存放局部变量表、操作数栈、动态链接、方法出口等信息。


本地方法栈: 本地方法栈的功能和虚拟机栈类似,本地方法栈为虚拟机用到的Native方法服务,一个Native Method就是一个java调用非java代码的接口,本地方法栈也会抛出StackOverFlow和OutOfMemoryError异常


java堆java堆可以说是java虚拟机中所管理的内存最大的一块,java堆被所有线程共享,虚拟机启动的时候创建。java堆中存放的对象实例的数组。几乎所有的对象实例以及数组都在堆上分配,java堆也是垃圾回收器管理的主要区域,java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,这和磁盘空间很相似。当一个堆无法再扩展时,会抛出OutOfMemoryError异常。


方法区: 方法区也是线程共享的内存区域,用于存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,java虚拟机对方法区的限制十分宽松,和java堆一样不需要连续的内存外,还可以选择不实现垃圾回收。


(二)Java虚拟机栈与程序计数器


虚拟机栈中保存的主要内容是栈帧,每次方法调用就会使得一个栈帧被压入到虚拟机栈。比如上一篇文章讲JVM字节码的时候,我们用到了这样一段代码:


publicclassMain {
publicstaticintcalculate(){
inta=1;
intb=2;
intc=(a+b)*10;
returnc;
    }
publicstaticvoidmain(String[] args) {
System.out.println(calculate());
    }
}

在JVM虚拟机栈中,结构就是这样的:

网络异常,图片无法展示
|


局部变量表存放了编译器可知的八个基本数据类型、对象引用、和returnAddress类型(指向了一条字节码指令的地址)。


操作数栈主要用来进行一系列出入栈的数值操作。


有关局部变量表、操作数栈、程序计数器更加详细的应用可以看我的前一篇文章:两张图让你快速读懂JVM字节码指令


动态链接:动态链接是值在程序运行期间将符号引用转换为直接引用。在一段代码中,类名、常量名、修饰符、对象名等都是符号引用,而如何通过符号找到具体的引用就需要动态链接做一层转换,将符号引用转换为直接引用。比如:JVM就能通过对象名就链接到堆中真实的对象。


动态链接的工作内容和类加载过程中解析这一步是一样的,只不过解析是将一些静态方法或变量(比如main()方法、static变量)替换为指向数据所存内存的直接引用。


方法出口:当一个方法执行之后,返回的方式可能是正常执行结束返回,也可能是抛出异常的返回。无论采用哪种方式,在方法退出之后都需要回到方法调用的位置,因此这些信息就会被保存到方法出口中。


JVM模式每个线程的虚拟机栈大小是1M,也可以通过-Xss调整虚拟机栈的大小。


(三)方法区


方法区是线程共享的内存区域,用于存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。关于方法区的概念,很多人其实都是浑的。方法区、永久代、元空间之间的区别大家都知道吗?


其实方法区是JVM规范中的一个概念,在不同的Java虚拟机以及不同版本的Java虚拟机中,方法区都有各自的实现。以最流行的HotSpot 虚拟机为例,在JDK1.8之前,方法区的实现叫做永久代,放在JVM内存之中。到了JDK1.8,方法区的实现变成了元空间,放在直接内存中。


(四)本地方法栈


本地方法栈的作用是在Java中调用非Java代码,他的功能和虚拟机栈类似。本地方法栈的存在应该算是历史遗留问题,Java刚出来的时候C、C++是当时绝对的统治者,因此在Java中免不了会去调用这一类代码,也因此需要本地方法栈。


(五)堆


堆是JVM虚拟机中最核心的部分了,绝大部分的垃圾回收都在堆中完成。


网络异常,图片无法展示
|


JVM堆分为新生代和老年代,默认比例为1:2,其中新生代又分为Eden区和两个

survivor区,比例为8:1:1。关于堆的大部分内容我已经放到垃圾回收部分进行讲解。


(六)总结


当真正去深入理解JVM虚拟机的时候,会发现它并不像想象中那么难,一个JVM虚拟机实际上就包含了这几样东西,最后再画张图描述一下常用JVM参数针对的位置。

网络异常,图片无法展示
|



相关文章
|
1天前
|
Java 程序员 编译器
Java内存模型深度解析与实践优化策略
在多线程编程领域,Java内存模型(Java Memory Model, JMM)是确保并发程序正确性的基石。本文深入探讨JMM的工作原理,结合最新研究成果和实际案例,揭示高效同步策略和避免常见并发缺陷的方法。文章不仅阐述理论,更注重实践,旨在为Java开发者提供全面的内存模型应用指南。
|
1天前
|
Java 程序员
深入理解Java内存模型(JMM)与并发编程
在Java并发编程领域,理解Java内存模型(JMM)是至关重要的。本文旨在通过数据导向的分析、科学严谨的论述和逻辑严密的结构,探讨JMM如何影响并发编程实践。我们将从JMM的基本概念出发,逐步深入到并发编程中的具体应用,包括同步机制、volatile关键字的作用以及线程间的通信。本文将引用权威研究与实验证据,结合经典理论,为读者提供全面的JMM知识框架,以促进对Java并发编程深层次的理解。
|
3天前
|
设计模式 缓存 Java
Java设计模式:享元模式实现高效对象共享与内存优化(十一)
Java设计模式:享元模式实现高效对象共享与内存优化(十一)
|
4天前
|
缓存 Java 程序员
Java内存模型深度解析:可见性、有序性和原子性
在多线程编程中,正确理解Java内存模型对于编写高效且无bug的并行程序至关重要。本文将深入探讨JMM的三大核心特性:可见性、有序性和原子性,并结合实例分析如何利用这些特性来避免常见的并发问题。
5 1
|
2天前
|
存储 安全 Java
Java内存模型:你需要知道的一切
Java内存模型:你需要知道的一切
|
2天前
|
Java
Java内存模型之原子性问题
Java内存模型之原子性问题
|
2天前
|
存储 缓存 Java
【Java并发基础】Java内存模型解决有序性和可见性
【Java并发基础】Java内存模型解决有序性和可见性
|
2天前
|
存储 缓存 Java
Java对象内存布局深度解析
Java对象内存布局深度解析
8 0
|
3天前
|
Java UED 开发者
JVM逃逸分析原理解析:优化Java程序性能和内存利用效率
JVM逃逸分析原理解析:优化Java程序性能和内存利用效率
|
4天前
|
存储 缓存 算法
ConcurrentHashMap的演进:从Java 8之前到Java 17的实现原理深度剖析
ConcurrentHashMap的演进:从Java 8之前到Java 17的实现原理深度剖析