JVM之内存区域

JVM内存区域

前言

学习java虚拟机,首先必须熟悉java虚拟机内存模型,为后续学习垃圾回收,性能监控,调优等内容打下坚实基础。

内存示意图

在这里插入图片描述

基本概念

一、堆(Java Heap)

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

java堆既可以被实现成固定大小的,也可以扩展,通过设置参数最大堆空间-Xmx和最小堆空间-Xms设定,若这两个参数设定大小相等那么就不可扩展,反之可扩展,当实例分配达到最大,无法在扩展是就会出现OutOfMemoryError异常。

堆也叫GC堆,就是GC最频繁的一块内存空间,所以在后续学习虚拟机垃圾回收机制,以及性能监控,调优等内容会详细学习。

二、方法区(Method Area)

方法区与java堆相同,是线程共享的,用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

常量池

class常量池、运行时常量池

其中常量池中存储的字面量和符号引用,字面量包括基本数据类型的值、被声明为final的常量值、文本字符串等;符号引用包括类和接口的完全限定名,字段名称和描述符,方法名称和描述符。

class常量池保存的就是类型信息,即符号引用部分,在运行期间会放置在运行时常量池中。

运行时常量池相对于class文件常量池能在运行时将新的常量添加到池中,运行时常量池由于受到方法区内存限制,也会出现OutOfMemoryError异常

三、java虚拟机栈(VM stack )

我们开发中经常提到堆栈,此处的栈一般就是值java虚拟机栈。它是“线程私有的”。

每个方法被执行的时候,java虚拟机都会同步创建一个栈帧用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每个方法被调用直至执行完毕的过程,对应着一个栈帧在虚拟机中从入栈到出栈的过程。

3.1 局部变量表

局部变量表存储了编译期可知的各种java虚拟机基本数据类型、对象引用类型和returnAddress类型。

也就是一个方法的参数,以及方法中的变量(局部变量),方法的返回值类型都会存储到java虚拟机栈中的局部变量表中。

示例:

    public String test(int i,long l,Object o){
        return "something";
    }
3.2 操作数栈

操作数栈记录的是在方法执行过程中产生的数据的存储,如
示例中i,i3

示例:

    public int test(int i1,int i2){
        int i = i1 + i2;
        int i3 = Math.abs(i);
        return i3;
    }
3.3 动态连接

每个栈帧都包含一个执行运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。

这里涉及到两个概念:动态连接和静态连接

Class文件中的常量池中存在大量的符号引用,字节码中的方法调用指令就以指向常量池的引用作为参数。

  • 部分符号引用在类加载阶段(解析)的时候就转化为直接引用,这种转化就是静态连接;
  • 部分符号引用在运行期间转化为直接引用,这种转化就是动态连接。
3.4 异常

java虚拟机栈涉及两种异常,一种是StackOverflowError异常,如果线程请求的栈深度大于虚拟机所允许的栈深度就会抛此异常;第二种OutOfMemoryError异常,如果java虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够内存,那么就会抛出此异常。

四、程序计数器(Program Counter Register)

程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器,所以每一个线程有各自的程序计数器,因此程序计数器是“线程私有的”。

字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖和这个计数器来完成。

程序计数器是唯一一个在《java虚拟就规范》中没有对顶任何OutOfMemoryError情况的区域。

五、本地方法栈(Native Method Stacks)

本地方法栈和java虚拟机栈相似,java虚拟机栈是为java方法服务的,而本地方法栈是为本地方法(Native)服务。

JVM内存结构变化

java8开始我们总会提到元空间,而且很多时候学习也会比较懵,元空间、永久代到底是怎么回事,下面一起学习。

按照java7以及前版本绘制一个内存结构示例图
在这里插入图片描述
这样通过示例图大概可以看到与开头的示例图有些区别,堆和方法拼接到了一块,为什么呢?

在《Java虚拟机规范》中将方法区描述为堆的一个逻辑部分,但是方法区还有一个别名“非堆”。

HotSpot虚拟就在开发中将GC分代扩展到了方法区,使用永久代来实现方法区
在这里插入图片描述

java8将字符串常量池、静态变量移动到了堆中,类型信息移动到了元空间中,永久代参数-XX:PermSize和-XX:MaxPermSize也失效了。
方法区存在于元空间中,通过本地内存实现。
在这里插入图片描述
元空间因为受到本地内存的限制也会出现OutOfMemoryError异常,但是可以通过-XX:MaxMetaspaceSize进行增长上限的最大值设置,默认值为4G,元空间的初始空间大小可以通过-XX:MetaspaceSize进行设置,默认值为20.8M,还有一些其他参数可以进行设置,元空间大小会自动进行调整。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值