【JVM】一、Java内存区域的介绍

注:本文资料收集自网络,一部分资料来源于大佬NO0b的博客,原博文链接:点我


JDK:Java开发工具    |   JRE:Java运行环境    |    JVM:Java虚拟机 (对应平台的虚拟机)

JVM(Java Virtual Machine),意为Java虚拟机

Java的内存区域

Java程序是交由JVM执行的,所以我们在谈Java内存区域划分的时候事实上是指JVM内存区域划分。在讨论JVM内存区域划分之前,先来看一下Java程序具体执行的过程:

首先Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行。

在整个程序执行过程中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。

因此,在Java中我们常常说到的内存管理就是针对这段空间进行管理(如何分配和回收内存空间)

 

根据《Java虚拟机规范》的规定,运行时数据区通常包括这几个部分:

程序计数器(Program Counter Register)、Java栈(VM Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)、堆(Heap)。

1.1 程序计数器(线程私有)

程序计数器是一块比较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。

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

如果正在执行的是一个Native方法,这个计数器值为空。

程序计数器内存区域是唯一一个在JVM规范中没有规定任何OOM情况的区域!

什么是线程私有?

由于在JVM中,多线程是通过线程轮流切换来获得CPU执行时间的。

因此,在任一具体时刻,一个处理器(多核处理器则指的是一个内核)都只会执行一条线程中的指令。那么,为了切换线程后能恢复到正确的执行位置,每条线程都需要独立的程序计数器,各条线程之间计数器互不影响,独立存储。我们就把类似这类区域称之为"线程私有"的内存。

因此,可以这么说:程序计数器是每个线程所私有的。

 

1.2 Java虚拟机栈(线程私有)

Java栈也称作虚拟机栈(Java Vitual Machine Stack)。

虚拟机栈描述的是Java方法执行的内存模型 : 每个方法执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈和出栈的过程。生命周期与线程相同。

当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。

之前我们一直讲的栈区域实际上就是此处的虚拟机栈,再详细一点,是虚拟机栈中的局部变量表部分。

局部变量表 : 存放了编译器可知的各种基本数据类型(8大基本数据类型)、对象引用和returnAddress类型(它指向了一条字节码指令的地址)。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在执行期间不会改变局部变量表大小。

此区域一共会产生以下两种异常:

1. 如果线程请求的栈深度大于虚拟机所允许的深度(-Xss设置栈容量),将会抛出StackOverFlowError异常。

2. 虚拟机在动态扩展时无法申请到足够的内存,会抛出OOM(OutOfMemoryError)异常

 

1.3 本地方法栈(线程私有)

本地方法栈与虚拟机栈的作用完全一样,他俩的区别无非是本地方法栈为虚拟机使用的Native方法服务,而虚拟机栈为JVM执行的Java方法服务。

在HotSpot虚拟机中,本地方法栈与虚拟机栈是同一块内存区域。

 

1.4 Java堆(线程共享)

Java中的堆是用来存储对象本身以及数组(当然,数组引用是存放在Java栈中的)。

在Java中,程序员基本不用去关心空间释放的问题,Java的垃圾回收机制会自动进行处理。因此这部分空间也是Java垃圾收集器管理的主要区域。

另外,堆是被所有线程共享的,在JVM中只有一个堆。

 

1.5 方法区(线程共享)

方法区在JVM中也是一个非常重要的区域,它与堆一样,是被线程共享的区域。

在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。

JVM规范规定:当方法区无法满足内存分配需求时,将抛出OOM异常。

 

运行时常量池是方法区的一部分,存放字面量与符号引用。它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。

字面量 : 字符串(JDK1.7后移动到堆中) 、final常量、基本数据类型的值。

符号引用 : 类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值