【深入理解JAVA虚拟机学习笔记二】栈,堆,方法区三者关系

本文详细探讨了Java虚拟机如何通过栈、堆和方法区管理内存。解释了句柄和直接指针两种对象访问方式的优缺点,以及它们对性能的影响。通过实例展示了线程栈的工作原理和栈帧的结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在我们访问一个对象时,JAVA虚拟机内部是通过栈上的reference数据来操作堆上的具体对象,同时方法区又存储着这个对象的类型数据即对象所属的类的信息。我们可以通过调用关系来了解堆、栈、方法区三者。
JAVA虚拟机规范中只规定了一个指向对象的引用,并没有定义这个引用应该通过哪种方式去定位、去找到对象所在堆中的具体位置,所以对象的方法方法是取决于虚拟机实现而定的。
现在主流的方法方式有两种:使用句柄和直接指针

通过句柄访问对象

在这里插入图片描述

  • 使用句柄访问的话,那么Java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含啥了对象的实例数据和类型数据各自的具体地址信息
  • 使用句柄访问的好处是reference中储存的是稳定的对象的句柄地址,当对象被移动(垃圾回收时进行对象移动)时候,只需要更新句柄中的对象实例部分指针,reference本身不用被修改。
    什么是句柄?
    句柄(Handle)来标示应用程序中不同的对象和同类中不同的实例。也可以理解为它是指向实例对象的指针的指针。
 			String s;//句柄
            String s1=new String();句柄=实例对象
            s1 = "a";//通过句柄操作对象

通过直接指针访问对象

在这里插入图片描述

  • 使用直接指针访问,那么Java堆中的布局中就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址
  • 使用直接指针访问的最大好处是 速度更快,它节省一次指针定位时间的开销(节省了句柄访问方法中的句柄池寻找实例池中的寻址时间),由于对象的访问在Java中非常频繁,因此这类开销积少成多时也是一项非常可观的成本。
  • 一般的虚拟机都是通过指针直接访问对象而通过句柄的这种方法并不是很常用。

举个栗子了解栈、堆、方法区
a b c是三个整型变量,Student是学生类,变量表中存储着 基本数据类型和引用类型的reference,主要以Student类来说明三者调用关系
在这里插入图片描述
由图可知,每个线程都要有一个线程栈,栈内存放栈帧,内部为线程中的变量表,既然是在栈中都要按照先入后出的原则进行入栈和出栈。
变量表中student指向堆中的student类实例的地址,同时指向方法区中Stud ent类的类型数据(类型数据存储类信息),内部还有其他引用类型的数据,这里举例String类型的name变量,student实例内部存储name由于是引用类型,也会使用指针,在堆中开辟存储空间存储name的内容存储内容“xiaoming”,实质是String类型,在方法区中也有对应类型指向。

详解栈的作用
  • 每当启动一个新线程的时候,java虚拟机都会为它分配一个java栈。java以栈帧为单位保存线程的运行状态。虚拟机只会对java栈执行两种操作:以栈帧为单位的压栈或者出栈。
  • 每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中
  • 每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
  • 栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
  • 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等

栈内存储着一个或多个重要的数据结构 – 栈帧
栈帧中的内容
局部变量表、操作数栈、动态链接、方法返回地址、附加信息。
栈帧的作用
每个方法的执行和结束对应着栈帧的入栈和出栈。
入栈表示被调用,出栈表示执行完毕或者返回异常。
一个虚拟机栈对应一个线程,当前CPU调度的那个线程叫做活动线程;一个栈帧对应一个方法,活动线程的虚拟机栈里最顶部的栈帧代表了当前正在执行的方法,而这个栈帧也被叫做‘当前栈帧’。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值