java对象模型 指令_深入理解多线程(二)—— Java的对象模型

上一篇文章中简单介绍过synchronized关键字的方式,其中,同步代码块使用monitorenter和monitorexit两个指令实现,同步方法使用ACC_SYNCHRONIZED标记符实现。后面几篇文章会从JVM源码的角度更加深入,层层剥开synchronized的面纱。

在进入正题之前,肯定有些基础知识需要铺垫,那么先来看一下一个容易被忽略的但是又很重要的知识点 —— Java对象模型 。

大家都知道的是,Java对象保存在堆内存中。在内存中,一个Java对象包含三部分:对象头、实例数据和对齐填充。其中对象头是一个很关键的部分,因为对象头中包含锁状态标志、线程持有的锁等标志。这篇文章就主要从Java对象模型入手,找一找我们关系的对象头以及对象头中和锁相关的运行时数据在JVM中是如何表示的。

Java的对象模型

任何一个接触过Java的人都知道,Java是一种面向对象语言。在学习Java的过程中你一定对下面两句话不陌生:

1、在面向对象的软件中,对象(Object)是某一个类(Class)的实例。 维基百科

我们还知道,在JVM的内存结构中,对象保存在堆内存中,而我们在对对象进行操作时,其实操作的是对象的引用。那么对象本身在JVM中的结构是什么样的呢?本文的所有分析均基于HotSpot虚拟机。

oop-klass model

HotSpot是基于c++实现,而c++是一门面向对象的语言,本身是具备面向对象基本特征的,所以Java中的对象表示,最简单的做法是为每个Java类生成一个c++类与之对应。但HotSpot JVM并没有这么做,而是设计了一个OOP-Klass Model。OOP(Ordinary Object Pointer)指的是普通对象指针,而Klass用来描述对象实例的具体类型。

为什么HotSpot要设计一套oop-klass model呢?答案是:HotSopt JVM的设计者不想让每个对象中都含有一个vtable(虚函数表)

这个解释似乎可以说得通。众所周知,C++和Java都是面向对象的语言,面向对象语言有一个很重要的特性就是多态。关于多态的实现,C++和Java有着本质的区别。

多态是面向对象的最主要的特性之一,是一种方法的动态绑定,实现运行时的类型决定对象的行为。多态的表现形式是父类指针或引用指向子类对象,在这个指针上调用的方法使用子类的实现版本。多态是IOC、模板模式实现的关键。

在C++中通过虚函数表的方式实现多态,每个包含虚函数的类都具有一个虚函数表(virtual table),在这个类对象的地址空间的最靠前的位置存有指向虚函数表的指针。在虚函数表中,按照声明顺序依次排列所有的虚函数。由于C++在运行时并不维护类型信息,所以在编译时直接在子类的虚函数表中将被子类重写的方法替换掉。

在Java中,在运行时会维持类型信息以及类的继承体系。每一个类会在方法区中对应一个数据结构用于存放类的信息,可以通过Class对象访问这个数据结构。其中,类型信息具有superclass属性指示了其超类,以及这个类对应的方法表(其中只包含这个类定义的方法,不包括从超类继承来的)。而每一个在堆上创建的对象,都具有一个指向方法区类型信息数据结构的指针,通过这个指针可以确定对象的类型。

上面这段是我从网上摘取过来的,说的有一定道理,但是也不全对。至于为啥,我会在后文介绍到Klass的时候细说。

关于opp-klass模型的整体定义,在HotSpot的源码中可以找到。

oops模块可以分成两个相对独立的部分:OOP框架和Klass框架。

在oopsHierarchy.hpp里定义了oop和klass各自的体系。

oop-klass结构

b7f0f543f17bf2c345579ff4e02f3613.png

oop体系:

//定义了oops共同基类typedefclassoopDesc*oop;//表示一个Java类型实例typedefclassinstanceOopDesc*instanceOop;//表示一个Java方法typedefclassmethodOopDesc*methodOop;//表示一个Java方法中的不变信息typedefclassconstMethodOopDesc*constMethodOop;//记录性能信息的数据结构typedefclassmethodDataOopDesc*methodDataOop;//定义了数组OOPS的抽象基类typedefclassarrayOopDesc*arrayOop;//表示持有一个OOPS数组typedefclassobjArrayOopDesc*objArrayOop;//表示容纳基本类型的数组typedefclasstypeArrayOopDesc*typeArrayOop;//表示在Class文件中描述的常量池typedefclassconstantPoolOopDesc*constantPoolOop;//常量池告诉缓存typedefclassconstantPoolCacheOopDesc*constantPoolCacheOop;//描述一个与Java类对等的C++类typedefclassklassOopDesc*klassOop;//表示对象头typedefclassmarkOopDesc*markOop;

上面列出的是整个Oops模块的组成结构,其中包含多个子模块。每一个子模块对应一个类型,每一个类型的OOP都代表一个在JVM内部使用的特定对象的类型。

从上面的代码中可以看到,有一个变量opp的类型是oppDesc ,OOPS类的共同基类型为oopDesc。

在Java程序运行过程中,每创建一个新的对象,在JVM内部就会相应地创建一个对应类型的OOP对象。在HotSpot中,根据JVM内部使用的对象业务类型,具有多种oopDesc的子类。除了oppDesc类型外,opp体系中还有很多instanceOopDesc、arrayOopDesc 等类型的实例,他们都是oopDesc的子类。

c25b66040ca350e159d296af726db8a9.png

这些OOPS在JVM内部有着不同的用途,例如,instanceOopDesc表示类实例,arrayOopDesc表示数组。也就是说,当我们使用new创建一个Java对象实例的时候,JVM会创建一个instanceOopDesc对象来表示这个Java对象。同理,当我们使用new创建一个Java数组实例的时候,JVM会创建一个arrayOopDesc对象来表示这个数组对象。

在HotSpot中,oopDesc类定义在oop.hpp中,instanceOopDesc定义在instanceOop.hpp中,arrayOopDesc定义在arrayOop.hpp中。

简单看一下相关定义:

classoopDesc {friendclassVMStructs;private:volatilemarkOop _mark;union_metadata {wideKlassOop _klass;narrowOop _compressed_klass;}_metadata;private:// field addresses in oopvoid*field_base(intoffset)const;jbyte*byte_field_addr(intoffset)const;jchar*char_field_addr(intoffset)const;jboolean*bool_field_addr(intoffset)const;jint*int_field_addr(intoffset)const;jshort*short_field_addr(intoffset)const;jlong*long_field_addr(intoffset)const;jfloat*float_field_addr(intoffset)const;jdouble*double_field_addr(intoffset)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/440516.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【POJ - 1651】Multiplication Puzzle(区间dp)

题干: The multiplication puzzle is played with a row of cards, each containing a single positive integer. During the move player takes one card out of the row and scores the number of points equal to the product of the number on the card taken …

java hive demo_java 操作hive通过jdbc

直接代码吧:记得要开启hive jdbc服务hive --service hiveserverpackage hive;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.Statement;public class HiveDemo {static{//注册jdbc驱动try {Class.forName(&…

【牛客 - 551D】CSL 的字符串(单调栈,思维)

题干: CSL 以前不会字符串算法,经过一年的训练,他还是不会……于是他打算向你求助。 给定一个字符串,只含有可打印字符,通过删除若干字符得到新字符串,新字符串必须满足两个条件: 原字符串中…

java 学生课程成绩_Java课设--学生成绩管理系统一

写在前面这个项目是Java课程的课设,一共花了5天的时间去完成它,在这期间感谢一些博主的帮助,让我了解到了一些新的技术知识,所以打算写这一系列博客来介绍一整个课设项目,也为了帮助之后的人,如有错误&…

【牛客 - 551E】CSL 的魔法(贪心,思维,STLmap,分块)

题干: 链接:https://ac.nowcoder.com/acm/contest/551/E 来源:牛客网 有两个长度为 n 的序列,a0,a1,…,an−1a0,a1,…,an−1和 b0,b1,…,bn−1b0,b1,…,bn−1。CSL 有一种魔法,每执行一次魔法,可以任意挑…

java调用cplex案例_【CPLEX教程03】java调用cplex求解一个TSP问题模型

前面我们已经搭建好cplex的java环境了,相信大家已经跃跃欲试,想动手写几个模型了。今天就来拿一个TSP的问题模型来给大家演示一下吧~CPLEX系列教程可以关注我们的公众号哦!获取更多精彩消息!01 TSP寤烘ā关于TSP建模,就…

【牛客 - 551C】CSL 的密码(后缀数组,后缀自动机,随机算法)

题干: 链接:https://ac.nowcoder.com/acm/contest/551/C 来源:牛客网 为了改变这一点,他决定重新设定一个密码。于是他随机生成了一个很长很长的字符串,并打算选择一个子串作为新密码。他认为安全的密码长度至少为…

java在一个类里实现存款_用Java编写一个简单的存款

package desposit.money;public class DespositMoney {public static void main(String[] args) {Customer c1 new Customer("第一个顾客",3);Customer c2 new Customer("第二个顾客",10);Customer c3 new Customer("第三个顾客",5);c1.start…

【牛客 - 551G】CSL的训练计划(二分 + 拓扑排序 + 优化卡常)

题干: 链接:https://ac.nowcoder.com/acm/contest/551/G 来源:牛客网 题目描述 众所周知,CSL 是一个负责的集训队队长。为了让集训队的学弟们训练更加饱和,他根据每个人的能力,提出了 m 个题数要求。假如…

java 自动启动监听_Spring Boot 启动事件和监听器,太强大了!

大家都知道,在 Spring 框架中事件和监听无处不在,打通了 Spring 框架的任督二脉,事件和监听也是 Spring 框架必学的核心知识之一。一般来说,我们很少会使用到应用程序事件,但我们也不要忘了它们的存在,比如…

【Gym - 101196F】Removal Game (环形区间dp,环状,细节优化)

题干&#xff1a; 健健开发了一个游戏叫做<<者护守形隐>>&#xff0c;里面有一个情节是这样的&#xff0c;女主子纯藤武被坏人关在了密室里&#xff0c;作为男主的肖健当然要英雄救美。但是要打开密室的门&#xff0c;必须解开一道谜题。 门上有几个数字围成的一个…

java day_Java_Day7(上)

Java learning_Day7(上)内容常用类枚举类型常用类String 类java.lang.String 类代表不可变的字符序列。String 类的常见构造方法&#xff1a;String(String original)创建一个 String 对象为 original 的拷贝。String(char[] value)用一个字符数组创建一个 String 对象。String…

【FZU - 2202】犯罪嫌疑人(思维,假装建图,分类讨论)

题干&#xff1a; 福尔摩斯是个大侦探&#xff0c;他总是在解决疑难案件。这一次的案件也不例外&#xff0c;案件是这样的&#xff1a;有编号为1到N的N位嫌疑犯&#xff0c;他们其中有一个犯了罪&#xff0c;然后每个嫌疑犯都被询问,“哪一个人犯了罪&#xff1f;”犯罪嫌疑人…

java关键字 valotile_Java内存模型-jsr133规范介绍,java中volatile关键字的含义

最近在看《深入理解Java虚拟机&#xff1a;JVM高级特性与最佳实践》讲到了线程相关的细节知识&#xff0c;里面讲述了关于java内存模型&#xff0c;也就是jsr 133定义的规范。系统的看了jsr 133规范的前面几个章节的内容&#xff0c;觉得受益匪浅。废话不说&#xff0c;简要的介…

【HDU - 5050 】Divided Land (Java大数,大数进制转换,大数gcd)

题干&#xff1a; It’s time to fight the local despots and redistribute the land. There is a rectangular piece of land granted from the government, whose length and width are both in binary form. As the mayor, you must segment the land into multiple squar…

Java重载和重写6_深入理解Java中的重写和重载

深入理解Java中的重写和重载重载(Overloading)和重写(Overriding)是Java中两个比较重要的概念。但是对于新手来说也比较容易混淆。本文通过两个简单的例子说明了他们之间的区别。定义重载简单说&#xff0c;就是函数或者方法有同样的名称&#xff0c;但是参数列表不相同的情形&…

【Gym - 101608G】WiFi Password (区间或,线段树 或 按位处理+尺取 或 二分)

题干&#xff1a; Just days before the JCPC, your internet service went down. You decided to continue your training at the ACM club at your university. Sadly, you discovered that they have changed the WiFi password. On the router, the following question wa…

java框架讲解ppt_经典框架spring介绍课件.ppt

Wepull Information Service Spring-javaEE的春天 预习检查 根据你的理解&#xff0c;“依赖注入”是什么&#xff1f; 根据你的理解&#xff0c;谈谈“依赖注入”适于在项目中应用吗&#xff1f; 你理解的“面向方面编程(AOP)”是什么样的&#xff1f; Spring框架的内容和作用…

python 协程池gevent.pool_进程池\线程池,协程,gevent

目录1. 进程池与线程池2. 协程3. gevent4. 单线程下实现并发的套接字通信首先写一个基于多线程的套接字服务端:from socket import *from threading import Threaddef comunicate(conn):while True: # 通信循环try:data conn.recv(1024)if len(data) 0: breakconn.send(data.…

【ZOJ - 3963】Heap Partition (STLset,二叉树的性质,构造,贪心,思维)

题干&#xff1a; A sequence S {s1, s2, ..., sn} is called heapable if there exists a binary tree Twith n nodes such that every node is labelled with exactly one element from the sequence S, and for every non-root node si and its parent sj, sj ≤ si and j…