JVM内存模型简介

JVM内存模型

本文主要是对JVM内存模型的一个简介,各个内存区域只是简单介绍功能,不会深入探究。

image-20230304092700422

这里的结构为jdk1.8版本。

JVM内存分为 程序计数器、虚拟机栈、本地方法栈、本地内存、堆内存几个区域。其中 程序计数器、虚拟机栈、本地方法栈属于线程私有。本地内存与堆属于线程共享

程序计数器

程序计数器属于线程私有,每条线程都有一个独立的程序计数器。

其主要作用是记录当前线程下一条JVM执行指令的地址,控制整个程序执行的流程。

Java虚拟机多线程是通过轮流切换并且分配线程执行时间来分配的。当前执行的线程如果分配的时间用完后就会被挂起,此时处理器会去处理其它线程。而当再次切换到该线程时,就需要程序计数器来确认当前线程接下来要执行的指令。

该区域不存在内存溢出,也不会进行GC操作。

虚拟机栈

虚拟机栈也是属于线程所独有的,并且它的生命周期与其所属的线程一致

虚拟机栈由多个栈帧组成,每个虚拟机栈中同时只能有一个栈帧活动。并且所有栈帧都遵循LIFO(后入先出)的原则。

栈帧:每次调用方法时占用的内存,其中存储着局部变量表操作数栈动态链接方法返回地址

  • 局部变量表:存放栈帧对应方法的局部变量信息
  • 操作数栈:主要用于保存计算过程中的中结果,同时作为计算过程中变量临时保存的地方
  • 动态链接:动态链接又称为指向运行时常量池方法的引用,主要用于确定该栈帧所属方法具体调用的对象

每个方法从开始调用到执行结束的过程,就为一个栈帧的入栈到出栈的过程。

虚拟机栈占用的内存是由方法调用产生的,当方法结束调用后会出栈,占用的内存也会归还。该区不会进行GC操作,但是可能导致内存溢出

栈内存溢出

一般发生原因可能有两种情况:

  • 方法调用的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。一般在递归方法中产生。

  • 如果虚拟机栈容量可动态扩展,当栈扩展时无法申请到足够的内存就会抛出OutOfMeeoryError异常。

使用递归方法模拟栈内存溢出
public class Main {

    public static void main(String[] args) {
        recursiveMethod();
    }

    private static void recursiveMethod() {

        for (int i = 0; i < 1000; i++) {
            recursiveMethod();
        }
    }
}

image-20230302235310591

本地方法栈

本地方法栈与虚拟机栈功能基本一样,也是属于线程私有,并且不会GC。

不同之处在于,虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则是为虚拟机使用到本地(Native)方法服务

本地方法:不属于Java代码编写的方法,即Java代码调用其它语言代码的一个接口。

Java堆

Java堆(Java Heap)是属于线程共享的区域,在JVM启动时创建。

该区域主要用于存放对象实例和数组,当该区域没有空间分配给实例,并且也无法再扩展时,会抛出OutOfMemoryError异常。

Java堆是垃圾收集器管理的区域,其主流结构一般分为以下几个区域:

  • 新生代:新生代一般被划分为三个区域,一个Eden空间和两个Survivor区域。
    • Eden区:Java所有新创建的对象实例和数组都会在该区域分区内存。
    • Survivor区:Survivor一般分为两个大小一样的区域,但同时只有一个区域会生效。主要用于GC时复制对象。
  • 老年代:老年代主要保存一些生命周期较长的对象。当对象再新生代经过多次复值后,达到一定的规则就会移入老年代。
  • 永久代:即jdk1.7及之前定义的方法区,也存放在Java堆中,于jdk1.8之后移出。

目前主流Java堆都属于可以动态扩展内存的区域,一般有两个参数:

  • -Xms:该参数指定Java堆起始初始内存大小。如-Xms1024m表示设置Java堆初始启动内存为1024M。
  • -Xmm:该参数指定Java堆最大内存大小,即属于堆可动态扩展内存的范围。如-Xmm2048m表示设置Java堆最大可分配内存为2048m。

本地内存

本地内存属于线程共享区域。在jdk1.8之后,本地内存可以看作两块区域组成(属于概念上的划分):

  • 直接内存(Direct Memory)
  • 元空间(Meta Space)

元空间(方法区)

元空间用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

在jdk8以前,被称为方法区(通常也被程序员称为永久代),属于Java堆的一个逻辑上的组成部分。

在jdk1.8之后,废除了永久代的概念,并将其改为在本地内存中使用元空间来实现。

该区域可以选择不实现垃圾回收器,但是如果无法满足新的内存分配需求时,也会抛出OutOfMemoryError异常。

直接内存

直接内存实际上并不属于JVM管理的内存区域,它是属于物理机内存。因此它不会受到Java堆大小的限制,但还是会受到本地总内存大小以及处理器寻址空间的限制。

在堆中的 DirectByteBuffer 对象来指向直接内存的地址,作为这块内存区域的引用来对其进行操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值