JVM内存模型

前引:市面上的虚拟机有很多,目前java中使用的虚拟机为HotSpot,java之所以能够具有可移植性,也是因为虚拟机的存在。在虚拟机中最重要的部分是运行时数据区(jvm内存结构),而运行时数据区(jvm内存结构)中最重要的部分就是堆内存,学习java虚拟机,包括jvm的调优基本都是对堆内存进行分析

目录

一、java程序的正常流程:

 二、虚拟机结构:

三、jVM内存结构:

1、本地方法栈:

2、程序计数器:

3、java栈(虚拟机栈):

(1)局部变量表:

(2)操作数栈:

(3)方法返回地址:

(4)动态链接:

4、方法区:

5、堆内存:

(1)新生代:

 (2)老年代:


一、java程序的正常流程:

1、编写java代码:按照业务需求编写java原生代码,一个原生代码文件就是一个“ *.java ”文件

2、编译java代码:如果想要去执行java源代码,则需要通过javac命令进行代码的编译处理,而后形成“ *.class ”(字节码文件),这个时候就相当于将源代码变成了虚拟机代码

3、运行java代码:

             (1)运行之前(虚拟机加载编译后的*.class文件):如果虚拟机代码想要被JVM执行,那么就需要通过ClassLoader的加载,也就是类加载,会将*.class文件中的信息保存在方法区中(一定要有CLASSPATH环境属性)

             (2)运行:其实也就是虚拟机通过执行引擎从方法区中加载到对应的程序代码并执行的过程,执行过程中虚拟机经常还需要调用一些本地的函数库

 二、虚拟机结构:

1、首先我们来看一下java虚拟机的整体结构

2、既然说java虚拟机中最重要的部分是运行时数据区(jvm内存结构),那么就来看看运行时数据区(jvm内存结构)中到底有些啥,我这里准备了两张图片第二张图片,在第二张图片中其实也包括了整体结构

(1)在第一张图中我们可以看到,jvm内存结构又可以分为线程独享和线程共享两类:

  • 线程共享区域:方法区、堆内存(在同一个堆内存空间被不同的栈内存访问会产出同步问题,可以使用synchronized、J.U.C来解决)
  • 线程独享区域:栈内存(保存的是一个地址信息(简单点理解就是对象名称))、程序计数器、本地方法栈          

(2)在第二张图中我们也可以看到java虚拟机的整体结构,从执行引擎处可以看出,java是一门既有解释,又有编译的语言

接下来将对这些部分进行解释,由易到难,由次要到主要

三、jVM内存结构:

1、本地方法栈:

        在java程序执行时需要调用本地操作系统所提供的C函数,这些操作虽然并不会受到jvm的限制,但是这些操作运行时所需要的数据都保存在了本地方法栈中

2、程序计数器:

         在编译字节码文件的时候会为每一条代码语句按执行顺序进行编号,在解释器执行字节码文件的时候就会依据这个编号依次向下执行。程序器中保存的是下一条指令的编号(其实保存的是下一条字节码的偏移地址,只是为了方便理解才成为编号,或者行号)                                                  值得注意的是:                                                                                                                                           当执行到下一条指令的时候,改变的只是程序计数器中保存的行号(字节码偏移地址)并不需要申请新的内存空间,因此永远都不会存在“OutOfMemoryError”内存溢出异常                                       另外,每一个线程都有自己独立的程序计数器,只会记录该线程的执行顺序,它属于线程私有区域,并且该区域所占用的内存空间非常小,可以忽略不计

3、java栈(虚拟机栈):

        每个线程都会存在私有的栈空间,在线程对象运行java代码时,每调用一次方法都会自动产生一个栈帧,然后将这个栈帧压入java栈,java栈遵循“后进先出”的栈数据结构的设计原则                          栈帧中主要包括:局部变量表、操作数栈、方法返回地址、动态链接

(1)局部变量表:

        是一组变量值存储的空间,用于存放方法参数和方法内部定义的所有局部变量,并且在其编译时就已经为其分配了会用到的最大容量。局部变量表的容量是以变量槽(slot)为最小的存储单位,每个变量槽都可以存储32位长度的数据,对于64位的数据类型,java虚拟机会将其写入两个连续的变量槽以实现数据存储

(2)操作数栈:

        在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据(入栈出栈),在进行表达式计算的时,会将所需数据先压栈,然后再弹出数据进行计算,最后将结果压栈。操作数栈的深度和局部变量表类似,都是在编译的时候进行所需最大空间的分配

(3)方法返回地址:

        每个方法执行完成后都需要返回到该方法的调用处

(4)动态链接:

        每个栈帧都包含一个可以指向当前方法所在类的运行时常量池(也就是指向方法区中该类信息的位置),这样在当前方法执行时如果调用其他方法,就可以通过运行时常量池找到对应的符号引用,然后将符号引用转为直接引用,最后实现方法调用

4、方法区:

首先需要清楚的一点是,方法区是一个逻辑概念,它分为两种实现,第一种是在JDK1.8之前的,被称为“永久代”。第二种是在JDK1.8及之后的,被称为“元空间”

我这里也准备了两张图片,方便理解其结构,以及区别

(1)通过第一张图片需要知道的是,方法区中存储了通过ClassLoader加载进JVM虚拟机的所有类信息。永久代存储在jvm内存中,元空间存储在本地内存。但是在逻辑概念上我们将其称为方法区, 并且在逻辑上,方法区属于java内存结构的一部分

问题:此时就会出现一个问题,为什么要将方法区从jvm内存中移除,而放在了物理内存中呢?

原因:存储在jvm内存中会与老年代绑定在一起,那么,不管是哪个空间内存不足,都会产生MajorGC,这样是得方法区的内存配置就会很麻烦,如果过大则浪费空间,如果过小又会频繁GC

(2)第二张图片中的常量池准确来说应该叫运行时常量池。通过这张图片需要清楚的是,StringTable(串池),每一个字符串常量都会被自动入池,也可以使用intern()方法将字符串手动入池

(3)既然方法区中存有类中的所有信息,那么问题来了,我程序中的代码是怎么与其产生联系的呢,这就要看图三所展示的结构了:

        当*.class文件被加载到方法区以后,内部采用的是instanceKlass(这是一个C++对象)来描述java类信息,同时会在堆中创建一个类的Class对象。_java_miror是instanceKlass对象的属性,也是堆内存中Class对象的一个java镜像,其中保存了此类在堆中的Class对象的地址。

        那对象与Class以及instanceKlass又是怎么联系起来的呢?以32位计算机为例:每个实例对象都会有一个8个字节大小的对象头,其中4个字节存储的就是堆内存中此类Class对象的地址,当我们的对象需要访问类中信息的时候,就会通过Class对象找到对应元空间的地址,然后在instanceKlass中获取需要的信息

(4)放上图五只为了更加清晰其结构:

5、堆内存:

下图是堆内存的结构划分:新生代、老年代、元空间(逻辑概念)

(1)新生代:

新生代又称为“年轻代”,用于保存所有新创建的对象,同时负责对象的老年代晋升

需要注意的是:From和To是一个相对的概念(之所以有两块一样大小的内存,是因为要使用复制算法),考虑到对象有可能被持续的长期的存储,所以这个时候存活区被设计为了两个(From、To),当伊甸园区的内存空间不足的时候,会将对象晋升到其中一个存活区(此时另外一个存活区的空间是空的),而后当这个存活区被存满的时候,会将当前存活区中的对象晋升到老年代,由于在实际开发之中新对象可能产生很多,所以伊甸园区和存活区的内存分配比为:8:1:1

 (2)老年代:

好了,本篇幅到这里就结束了,关于JVM的内容其实还有很多没有总结,比如垃圾回收算法,垃圾收集器,数据引用(直接引用,弱引用,软引用,虚引用,终结器引用),JVM控制工具,ClassLoader类加载,伊甸园区的算法,对象引用方式,以及JVM调优方面都还没有总结出来,这些东西以后我再更新出来吧!!!!

其实以上内容中有一些细节的地方我也没有列举出来,因为有些东西牵扯的比较多,都已经涉及到其他的知识了,而且比较杂,因此没有列举,这部分如果之后有机会再进行总结吧!!!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值