每日一面——从JVM层面谈谈你对“对象”的理解
菜鸡每日一面系列打卡25天
每天一道面试题目
助力小伙伴轻松拿offer
坚持就是胜利,我们一起努力!
题目描述
从JVM层面谈谈你对“对象”的理解。
题目分析
在开始之前,菜鸡想先引用一句非常经典的话,“Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来。”这简直是程序员版的现实围城。而这段话里提到的内存动态分配和垃圾收集技术,都与“对象”这个词脱不了干系。
众所周知(对了解Java的人而言),Java是一门面向对象的语言。“对象”这个概念已经深入了每个面向对象语言程序员的内心,这包括但不限于Java、C++、Python……而本文将要探究的就是JVM层面对象的概念。理解了这一概念,会对面向对象有更加深刻的认识。
题目解答
01
对象的创建
在Java的世界里永远不缺“对象”,如果缺,new一个。就是这个神奇的new关键字,分分钟解决了现实世界中找“对象”的难题。究竟是怎么做到的呢?这种神秘的力量值得我们仔细研究一波。注意,下文所提到的对象仅限于普通Java对象,不包括数组和Class对象等。
首先,需要了解Java程序运行的大致过程,我们编写的源程序(.java文件)经过编译器编译之后得到(.class文件),这也是Java跨平台的关键,然后JVM将字节码文件解释成机器码运行。
接下来,我们用一张图来描述当JVM遇到一条字节码的new指令时的反应。
注意,这张图仅仅描述的是JVM层面创建对象的流程,至此,其实并没有得到你想要的对象,后续会执行Class文件中的<init>()方法进行对象初始化。
02
对象的内存布局
第一部分的图中中提到了对象头这个概念。在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:对象头、实例数据和对齐填充。
对象头的内容可分为两部分:Mark Word和类型指针。
Mark Word的内容如下表所示:
类型指针(非必须)则是对象指向它的类型元数据的指针,JVM通过这个指针来确定该对象是哪个类的实例。
实例数据存储的是对象的有效信息,即我们在程序中定义的类的属性(包括从父类继承的)。
对齐填充起到占位符的作用。HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,也即任何对象的大小都必须是8字节的整数倍。对象头部分已经被设计成天然满足8字节的整数倍了,而对象的实例数据部分如果不满足,就需要进行对齐填充。
03
对象的访问定位
常见的对象访问定位方式主要有两种:句柄访问,直接指针访问。
-
句柄访问:
过程
① reference → 句柄池(包括实例数据指针与类型数据指针)
②实例数据指针 → 对象实例数据、类型数据指针 → 对象类型数据
优势
reference中存储的是稳定句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而不改变reference。
-
直接指针访问:
过程
①reference → 对象实例数据
②对象实例数据 → 对象类型数据
优势
速度更快,节省了一次指针定位的时间开销。
参考资料
《深入理解Java虚拟机》第3版 周志明
相关链接
以上便是菜鸡对JVM层面对象的一些总结,供大家参考。
学习 | 工作 | 分享
????长按关注“有理想的菜鸡”
只有你想不到,没有你学不到