【JVM】JVM五大内存区域介绍

这篇具有很好参考价值的文章主要介绍了【JVM】JVM五大内存区域介绍。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

 一、程序计数器(线程私有)

二、java虚拟机栈(线程私有)

2.1、虚拟机栈

2.2、栈相关测试

2.2.1、栈溢出

三、本地方法栈(线程私有)

四、java堆(线程共享)

五、方法区(线程共享)

六、实例演示


        Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而一直存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。

【JVM】JVM五大内存区域介绍,jvm

 一、程序计数器(线程私有)

        程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在Java虚拟机的概念模型里 [1] ,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
        由于Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

二、java虚拟机栈(线程私有)

2.1、虚拟机栈

        与程序计数器一样,Java虚拟机栈(Java Virtual Machine Stack)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧 [1] (Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

        “栈”通常就是指这里讲的虚拟机栈,或者更多的情况下只是指虚拟机栈中局部变量表部分。
局部变量表存放了编译期可知的各种Java虚拟机基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用
(reference类型,它并不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。
        这些数据类型在局部变量表中的存储空间以局部变量槽(Slot)来表示,其中64位长度的long和double类型的数据会占用两个变量槽,其余的数据类型只占用一个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。请读者注意,这里说的“大小”是指变量槽的数量,虚拟机真正使用多大的内存空间(譬如按照1个变量槽占用32个比特、64个比特,或者更多)来实现一个变量槽,这是完全由具体的虚拟机实现自行决定的事情。

2.2、栈相关测试

2.2.1、栈溢出

测试类:

如果某个线程的线程栈的内存被耗尽,没有足够的内存资源去创建栈帧,就会发生内存溢出。

public class TestStack {
    public static void main(String[] args) {
        test();
    }
    public static void test(){
        test();
    }
}

结果:

【JVM】JVM五大内存区域介绍,jvm

        上面这串代码的执行过程是:线程先执行main方法,同时会创建main方法的栈帧插入到该线程的线程栈中,当执行到test()方法时,创建test()方法的栈帧插入到该线程的线程栈中,执行到test()方法里的test()方法时,创建栈帧,插入到线程栈中,后面进行不断创建栈帧、入栈。当创建一定数量的栈帧后,剩下的线程资源无法再创建新的栈帧就会报StackOverflowError异常(堆栈溢出异常)(当前虚拟机栈不可以动态扩展)

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

三、本地方法栈(线程私有)

        本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别只是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native)方法服务。

四、java堆(线程共享)

        Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,Java世界里“几乎”所有的对象实例都在这里分配内存。

        Java堆是垃圾收集器管理的内存区域,因此一些资料中它也被称作“GC堆”(Garbage CollectedHeap)。从回收内存的角度看,由于现代垃圾收集器大部分都是基于分代收集理论设计的,所以Java堆中经常会出现“新生代”“老年代”“永久代”“Eden空间”“From Survivor空间”“To Survivor空间”等名词。

        如果从分配内存的角度看,所有线程共享的Java堆中可以划分出多个线程私有的分配缓冲区
(Thread Local Allocation Buffer,TLAB)
,以提升对象分配时的效率。不过无论从什么角度,无论如何划分,都不会改变Java堆中存储内容的共性,无论是哪个区域,存储的都只能是对象的实例,将Java堆细分的目的只是为了更好地回收内存,或者更快地分配内存。

        Java堆既可以被实现成固定大小的,也可以是可扩展的,不过当前主流的Java虚拟机都是按照可扩展来实现的(通过参数-Xmx和-Xms设定)。如果在Java堆中没有内存完成实例分配,并且堆也无法再扩展时,Java虚拟机将会抛出OutOfMemoryError异常。

五、方法区(线程共享)

        方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

        如果方法区无法满足新的内存分配需求时,将抛出OutOfMemoryError异常。

六、实例演示

1、基本数据类型

实体类

@Data
public class UserParam {

    /**
     * 用户名
     */
    private String userName;
    /**
     * 密码
     */
    private String password;
    /**
     * 昵称
     */
    private String nickName;

    /**
     * 旧密码
     */
    private String oldPassWord;

    /**
     * 新密码
     */
    private String newPassWord;

}

测试

public class TestStack {
    public static void main(String[] args) {
        UserParam userParam=new UserParam();
        int b=1;
        test(userParam,b);
        test(userParam,b);
        System.out.println(userParam);
    }
    public static void test(UserParam userParam,int a){
        userParam.setUserName(String.valueOf(a));
        a=2;
    }
}

结果:

【JVM】JVM五大内存区域介绍,jvm

分析:

b变量是基本数据类型,创建完在栈帧中,没有任何引用,参数也只是传入值,方法中a改变对b没有任何影响。

 2、引用数据类型会根据传入的引用数据的改变而改变

public class TestStack {
    public static void main(String[] args) {
        UserParam userParam=new UserParam();
        userParam.setNickName("张三");
        test(userParam);
        test(userParam);
        System.out.println(userParam);
    }
    public static void test(UserParam userParam){
        userParam.setUserName(userParam.getNickName());
        userParam.setNickName("李四");
    }
}

结果:

【JVM】JVM五大内存区域介绍,jvm

分析:

将对象作为参数传入时,test方法中的对象也是指向同一片内存区域,操作的是同一块内存,所以在test方法中改变属性的值会影响外边同一个对象内的属性值。文章来源地址https://www.toymoban.com/news/detail-616382.html

到了这里,关于【JVM】JVM五大内存区域介绍的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • jvm的内存区域

    JVM 内存分为线程私有区和线程共享区,其中方法区和堆是线程共享区,虚拟机栈、本地方法栈和程序计数器是线程隔离的数据区。 1)程序计数器 程序计数器(Program Counter Register)也被称为 PC 寄存器,是一块较小的内存空间。 它可以看作是当前线程所执行的字节码的行号指

    2024年02月10日
    浏览(38)
  • JVM内存区域

    为了更好的理解类加载和垃圾回收,先要了解一下JVM的内存区域(如果没有特殊说明,都是针对的是 HotSpot 虚拟机。)。 Java 源代码文件经过编译器编译后生成字节码文件,然后交给 JVM 的类加载器,加载完毕后,交给执行引擎执行。在整个执行的过程中,JVM 会用一块空间来

    2024年02月13日
    浏览(42)
  • JVM | Java内存区域

    以上笔记基于JavaGuide整理 JDK 1.8: 线程私有 的:程序计数器,虚拟机栈,本地方法栈 线程共享 的:堆,方法区(元空间),直接内存 (非运行时数据区的一部分) 程序计数器有两个作用: 字节码解释器通过改变程序计数器来依次读取指令,从而 实现代码的流程控制 ,如:顺

    2024年02月08日
    浏览(79)
  • JVM内存区域划分

    简介:JVM有很多个不同版本的实现;其中HotSpot VM是最主流使用的JVM;Oracle官方jdk和开源openjdk都是使用这个JVM JVM内存区域划分:按每个区域不同功能划分;相互之间不会干扰 本地方法栈 native:表示是JVM内部C++代码;给调用JVM内部方法准备的栈空间。存储本地方法native之间调

    2024年02月12日
    浏览(37)
  • JVM——Java 内存区域详解

    如果没有特殊说明,都是针对的是 HotSpot 虚拟机。 基本问题 介绍下 Java 内存区域(运行时数据区) Java 对象的创建过程(五步,建议能默写出来并且要知道每一步虚拟机做了什么) 对象的访问定位的两种方式(句柄和直接指针两种方式) 拓展问题 String 类和常量池 8 种基本

    2024年02月13日
    浏览(41)
  • JVM内存模型/运行时数据区域

    java虚拟机管理这块内存,所以我们也叫运行时数据区域 这里按线程是否共享来分类,所谓线程不共享就是每个线程里面都会配一套 程序计数器 栈, 互相不干涉。 而方法区和堆是线程所有共享 意味着只有一个(这里注意堆是实际概念 方法区是一个虚拟概念) 注意:程序计

    2024年01月18日
    浏览(53)
  • JVM哪些区域会出现内存溢出

    JVM(Java Virtual Machine)是指Java虚拟机,是一种可以在不同平台上运行Java字节码的虚拟计算机。JVM是Java语言的核心,通过将Java代码编译成字节码并在JVM上运行,实现了跨平台的特性。 1.方法区(Metaspace) 方法区用于存储类的信息、静态变量和常量等数据。在JDK8及以上版本中

    2024年02月08日
    浏览(42)
  • JVM运行时区域——对象创建内存分配过程

            新创建的对象 , 都存放在伊甸园区域 ,当垃圾回收时,将伊甸园区域的垃圾数据销毁,然后将存活的对象转移到幸存者0区域,之后创建的新的对象还是存放在伊甸园区域,等到再次垃圾回收后,将伊甸园区域和幸存者0区域中存活的对象一起转移到幸存者1区域中

    2024年02月15日
    浏览(46)
  • JVM篇--Java内存区域高频面试题

    首先我们要知道java堆空间的产生过程: 即当通过java命令启动java进程的时候,就会为它分配内存,而分配内存的一部分就会用于创建堆空间,而当程序中创建对象的时候 就会从堆空间来分配内存,所以堆空间存放的主要是对象和数组; 而GC 其实说白了就是java虚拟机回收对象

    2024年02月01日
    浏览(51)
  • 深入理解 JVM 之——Java 内存区域与溢出异常

    更好的阅读体验 huge{color{red}{更好的阅读体验}} 更好的阅读体验 本篇为深入理解 Java 虚拟机第二章内容,推荐在学习前先掌握基础的 Linux 操作、编译原理、计算机组成原理等计算机基础以及扎实的 C/C++ 功底。 该系列的 GitHub 仓库:https://github.com/Doge2077/learn-jvm Java 虚拟机在

    2024年02月09日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包