在继续了解Java内存模型之前,最好先理解Java对象的内存表示。在网上搜了下Java对象内存表示,说得都不够系统和到位。之前看了《Hotspot实战》一书,对JVM如何表示对象这块说得挺好,推荐一下。如果不理解JVM运行时的各种内存区域以及Java调用的过程,那么很难把Java内存模型理解到位。这个是一个比较大的主题,以后会陆续写一些JVM相关的。这里单把Java对象的内存拿出来聊聊,文中内容都基于Hotspot虚拟机。

Hotspot主要是用C++写的,所以它定义的Java对象表示模型也是基于C++实现的。

Java对象的表示模型叫做“OOP-Klass”二分模型,包括两部分:

1. OOP,即Ordinary Object Point,普通对象指针。说实话这个名称挺难理解。说白了其实就是表示对象的实例信息

2. Klass,即Java类的C++对等体,用来描述Java类,包含了元数据和方法信息

一个Java对象就包括两部分,数据和方法,分别对应到OOP和Klass。最简单的理解就是如果让你自己用Java语言来开发一套新的语言,你如何来表示这个新的语言的对象呢。肯定也是类似的思路,一个模块是用Java类来实现表示数据的部分,一个模块是用Java类实现表示方法和元数据的部分。

JVM运行时加载一个Class时,会在JVM内部创建一个instanceKlass对象,表示这个类的运行时元数据。创建一个这个Class的Java对象时,会在JVM内部相应的创建一个instanceOop来表示这个Java对象。熟悉JVM的同学可以明白,instanceKlass对象放在了方法区,instanceOop放在了堆,instanceOop的引用放在了JVM栈。

JVM是基于栈来运行的,当一个线程调用一个对象的方法时,会在它的JVM栈的栈顶创建一个栈帧(Frame)的数据结构,这个数据结构是用来保存方法的局部变量,操作数栈,动态连接和方法返回值的。通过参数传递的值和在方法中new出来的对象的引用都保持在局部变量表里面。

Java的方法调用是值传递,不是引用传递,原因就在这里,传递进来的参数相当于在局部变量表里面拷贝了一份,实际计算时,操作数栈操作的是局部变量变量里面的值,而不是外部的变量。

在堆中创建的Java对象实际只包含数据信息,它包含三部分:

1. 对象头,也叫Mark Word

2. 元数据指针,可以理解为类对象指针,指向方法区的instanceKlass实例

3. 实例数据

如果是数据对象的话,还多了一个部分,就是数组长度。

对象头主要存储对象运行时记录信息,如hashcode, GC分代年龄,锁状态标志,偏向线程ID,偏向时间戳等。对象头的长度和JVM的字长一致,比如32位JVM的对象头是32位,64位JVM的对象头是64位。

这里可以看到,所谓的给一个对象加锁,其实就是设置了对象头某些位。当其他线程看到这个对象的状态是加锁状态后,就等待释放锁。

在方法区的instanceKlass对象相当于Class加载后创建的运行时对象,它包含了运行时常量池,字段,方法等元数据,当调用一个对象的方法时,如上面的图所示,实际定位到了方法区的instanceKlass对象的方法元数据。

下面我们通过一个实例,使用HSDB来看看运行时的instanceKlass和instanceOop到底是什么样的。在方法区

创建一个Person类,有name, age, sex实例属性,有一个sayHi方法

 
  1. package main;

  2. public class Person {

  3.     private String name;

  4.     private int age;

  5.     private boolean sex;

  6.     

  7.     public void sayHi(){

  8.         System.out.println("Say hi from ITer_ZC");

  9.     }

  10.     

  11.     public static void main(String[] args){

  12.         Person p = new Person();

  13.         p.sayHi();

  14.         

  15.         try {

  16.             Thread.sleep(500000);

  17.         } catch (InterruptedException e) {

  18.             e.printStackTrace();

  19.         }

  20.     }

  21. }

HSDB是一款内置与SA的GUI调试工具,集成了各种JVM监控工具,可以用来深入分析JVM内部状态。

启动HSDB:

java -cp ${JAVA_HOME}/lib/sa-jdi.jar sun.jvm.hotspot.HSDB

运行Person,使用JPS查看进程ID

使用HSDB attach Person进程

Attach成功后看到21461进程里的各个子进程

在Class Browser里面找到Person对应的instanceKlass的运行时实例

在inspector里面查看0x000000077fc82328这个对象实例,我们可以看到instanceKlass的字段,方法,运行时常量池,父类,兄弟类等元数据信息

在Object Histogram里面找到main.Person对象

查看main.Person Oop的运行时实例

_mark就是对象头,接着是实例数据信息。HSDB没有显示类对象指针

聊聊高并发(四)Java对象的表示模型和运行时内存表示相关推荐

  1. Java 虚拟机(JVM)运行时内存结构

    1.PC Register(pc寄存器) Java虚拟机线程都有自己的pc寄存器.一条Java虚拟机线程只会同时执行一个方法的代码,这个方法称为该线程的当前方法.如果这个方法不是native的,那么p ...

  2. 聊聊高并发(三十六)Java内存模型那些事(四)理解Happens-before规则

    在前几篇将Java内存模型的那些事基本上把这个域底层的概念都解释清楚了,聊聊高并发(三十五)Java内存模型那些事(三)理解内存屏障 这篇分析了在X86平台下,volatile,synchronize ...

  3. 聊聊高并发(二十二)解析java.util.concurrent各个组件(四) 深入理解AQS(二)

    上一篇介绍了AQS的基本设计思路以及两个内部类Node和ConditionObject的实现 聊聊高并发(二十一)解析java.util.concurrent各个组件(三) 深入理解AQS(一) 这篇 ...

  4. 聊聊高并发(二十七)解析java.util.concurrent各个组件(九) 理解ReentrantLock可重入锁

    这篇讲讲ReentrantLock可重入锁,JUC里提供的可重入锁是基于AQS实现的阻塞式可重入锁.这篇 聊聊高并发(十六)实现一个简单的可重入锁 模拟了可重入锁的实现.可重入锁的特点是: 1. 是互 ...

  5. 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore

    前几篇分析了一下AQS的原理和实现,这篇拿Semaphore信号量做例子看看AQS实际是如何使用的. Semaphore表示了一种可以同时有多个线程进入临界区的同步器,它维护了一个状态表示可用的票据, ...

  6. 聊聊高并发(二十一)解析java.util.concurrent各个组件(三) 深入理解AQS(一)

    AQS是AbstractQueuedSynchronizer的缩写,AQS是Java并包里大部分同步器的基础构件,利用AQS可以很方便的创建锁和同步器.它封装了一个状态,提供了一系列的获取和释放操作, ...

  7. 聊聊高并发(二十)解析java.util.concurrent各个组件(二) 12个原子变量相关类

    这篇说说java.util.concurrent.atomic包里的类,总共12个,网上有很多文章解析这几个类,这里挑些重点说说. 这12个类可以分为三组: 1. 普通类型的原子变量 2. 数组类型的 ...

  8. 聊聊高并发(十七)解析java.util.concurrent各个组件(一) 了解sun.misc.Unsafe类

    了解了并发编程中锁的基本原理之后,接下来看看Java是如何利用这些原理来实现各种锁,原子变量,同步组件的.在开始分析java.util.concurrent的源代码直接,首先要了解的就是sun.mis ...

  9. 聊聊高并发(三十三)Java内存模型那些事(一)从一致性(Consistency)的角度理解Java内存模型

    可以说并发系统要解决的最核心问题之一就是一致性的问题,关于一致性的研究已经有几十年了,有大量的理论,算法支持.这篇说说一致性这个主题一些经常提到的概念,理清Java内存模型在其中的位置. 一致性问题更 ...

最新文章

  1. 如何成为一名现代的Linux程序员
  2. Python3|Opencv——添加高斯噪声Gauss Noise
  3. 怎么查看oracle数据库数据量大小?
  4. cuda 5.0配置vs2008+Visual Assist X +安装问题解决
  5. Fiori应用里如何给客户主数据维护图片
  6. CF407 E. k-d-sequence
  7. 怎么用代码制作WordPress的归档页面
  8. 机器学习必备:前20名Python人工智能和机器学习开源项目
  9. IOS硬件解码VTDecompressionSession失效
  10. 388. Longest Absolute File Path
  11. UI常见面试题-整体素养篇
  12. 论文笔记 Object-Aware Instance Labeling for Weakly Supervised Object Detection - ICCV 2019
  13. 毕业设计论文选题系统系统用例图_毕业设计论文选题系统
  14. [imx8mpevk] pcie endpoint test
  15. tomacat出错_繁星漫天_新浪博客
  16. java derby数据库_使用Apache Derby进行Java数据库开发,第1部分
  17. 渲染的艺术:建筑效果图渲染的5个成功要素
  18. java 中boolean与Boolean的区别
  19. 【Matlab人脸识别】KL变换人脸识别【含GUI源码 859期】
  20. 137813-35-5,cyclo(Arg-Gly-Asp-D-Phe-Val)分子式:C26H38N8O7

热门文章

  1. switch语句格式_JavaScript流程控制语句_if语句(十一)
  2. oracle ora01732,一天一小步_2008.5.02: ora-01732错误
  3. java如何接受字符_java中string怎么获取指定位置的字符
  4. 什么是java序列化,如何实现java序列化?
  5. linux脚本文件个数,Linux上面执行mysql脚本判断文件个数
  6. spring图片转视频_一直在用的 Spring,你知道它的加载原理吗?
  7. mysql rowdatapacket_arrays – 将此RowDataPacket对象数组缩小为单个对象
  8. python怎样遍历列表中数字_关于Python列表的遍历和数字列表
  9. wmm开启和关闭的区别_【解读】排烟风机应由哪些排烟防火阀连锁关闭
  10. html鼠标点击伪类,CSS伪类:CSS3鼠标滑过按钮动画