加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

JVM内存结构

发布时间:2020-12-14 06:40:37 所属栏目:Java 来源:网络整理
导读:按照Java虚拟机规范的规定,JVM自动管理的内存将包括以下几个运行时的数据区域: 下面分别对几个数据区域进行说明: 1.程序计数器 程序计数器是JVM中一块较小的内存区域,保存着当前线程执行的虚拟机字节码指令的内存地址. Java多线程的实现,其实是通过线程间的

按照Java虚拟机规范的规定,JVM自动管理的内存将包括以下几个运行时的数据区域:

JVM内存结构

下面分别对几个数据区域进行说明:

1.程序计数器

程序计数器是JVM中一块较小的内存区域,保存着当前线程执行的虚拟机字节码指令的内存地址.

Java多线程的实现,其实是通过线程间的轮流切换并分配处理器执行时间的方式实现的,在任何时刻,处理器都只会执行一个线程的指令. 在多线程场景下,为了保证线程切换回来后,还能恢复到原来的状态,找到原先执行的指令,所以每个线程都会设立一个程序计数器,并且各个线程之间互不影响,程序计数器为"线程私有"的内存区域.

若当前线程正在执行的是Java方法,则程序计数器保存的是虚拟机字节码的内存地址,若正在执行的Native方法(非Java方法),则程序计数器为空.

程序计数器是唯一一个在Java规范中没有规定任何OutOfMemory(内存耗尽)场景的区域

2.虚拟机栈

虚拟机栈和线程是紧密联系的,每创建一个线程就会对应创建一个Java栈,生命周期和线程相同,所有虚拟机栈也是"线程私有"的内存区域.

这个栈中对应多个栈帧,每调用一个方法就会往栈中创建并压入一个栈帧,栈帧是用来存储方法数据和部分过程结果的数据结构,每一个方法从调用到最终返回结果的过程,就对应一个栈帧从入栈到出栈的过程.

线程运行过程中,只有一个栈帧处于活跃状态,被称为"当前活动帧栈",当前活动帧栈始终是虚拟机栈的栈顶元素.

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

  1. 若线程请求的栈深度太深,超出了虚拟机所允许的深度,就会出现StackOverFlowError(比如无限递归)
  2. 虚拟机栈可以动态扩展,若扩展到无法申请足够的内存空间,就会出现OOM

3.本地方法栈

本地方法栈和虚拟机栈的作用相似,只是虚拟机栈是为Java方法服务的,而本地方法栈是为Native方法服务的.

4.方法区

方法区是用来存储类结构信息(包括常量池、静态变量、构造函数等)的地方,类型信息是由类加载器在类加载是从类文件中提取出来的

方法区存在着垃圾回收,因为用户通过自定义加载器加载的一些类同样会成为垃圾,JVM会回收一个未被引用类所占的空间,以使方法区的空间最小

方法区是线程共享的.

5.堆

堆是存储java实例或者对象的地方,是GC的主要区域,同样也是线程共享的内存区域.


下面举几个例子来说明:

JVM内存结构

JVM内存结构

上面的main方法中运行过程如下:

  1. 用户创建了一个Student对象,运行时JVM首先到方法区寻找该对象的类型信息,没有则使用类加载器将Student.class字节码文件加载至6内存中的方法区,并将Student类的类型信息存放至方法区
  2. 然后JVM在堆中为新的Student实例分配内存空间,这个实例持有着指向方法区的Student类型信息的引用(类型信息在方法区中的内存地址)
  3. 在运行的JVM进程中,会首先运行一个线程执行此用户程序,而创建线程的同时也创建了一个虚拟机栈,虚拟机栈用来跟踪线程运行中的一系列方法调用过程,每调用一个方法就会创建一个栈帧并压入栈中. 上面的stu是对Student的引用,存放在栈中,指向堆中Student实例的内存地址.
  4. JVM根据stu引用持有的堆中对象地址,定位到堆中的Student实例,由堆中实例指向的方法区Student类型信息引用,获得add()方法的字节码信息,然后就可以执行add()方法的指令了

总结

一、方法区、堆是线程共享的。 虚拟机栈、本地方法栈和程序计数器是线程私有的

二、栈中:

  1. 每个线程有一个虚拟机栈, 栈中保存基础数据类型的对象和自定义对象的引用,对象实例存放在堆区中
  2. 方法的形式参数,方法调用玩后从栈空间收回
  3. 引用对象的地址,引用完后,栈空间地址立即被回收,堆空间等待GC

三、堆中:

  1. 存储的全是对象实例, 每个对象包含一个与之对象的class信息,存放在方法区
  2. JVM只有一个堆区,被所有线程共享,堆区中不存放基本类型和对象引用,只存放对象实例

四、方法区中:

  1. 存放线程执行的字节码指令
  2. 被所有线程共享,其中包含所有的class和static变量
  3. 常量池位于方法区中,例如String的常量池

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读