JVM视角看对象创建
从jvm处理对象的流程来看,大概分成三步骤:1.如何创建。2.什么是最佳存储模型。3.如何访问。本文将按照这三个流程进行讲解。
一、对象的创建过程
1. 拿到内存创建指令
当虚拟机遇到内存创建的指令的时候(new 类名),来到了方法区,找 根据new的参数在常量池中定位一个类的符号引用。
2. 检查符号引用
检查该符号引用有没有被加载、解析和初始化过,如果没有则执行类加载过程,否则直接准备为新的对象分配内存
3. 分配内存
虚拟机为对象分配内存(堆)分配内存分为指针碰撞和空闲列表两种方式;分配内存还要要保证并发安全,有两种方式。
3.1. 指针碰撞
所有的存储空间分为两部分,一部分是空闲,一部分是占用,需要分配空间的时候,只需要计算指针移动的长度即可。
3.2. 空闲列表
虚拟机维护了一个空闲列表,需要分配空间的时候去查该空闲列表进行分配并对空闲列表做更新。
可以看出,内存分配方式是由java堆是否规整决定的,java堆的规整是由垃圾回收机制来决定的
3.2.5 安全性问题的思考
假如分配内存策略是指针碰撞,如果在高并发情况下,多个对象需要分配内存,如果不做处理,肯定会出现线程安全问题,导致一些对象分配不到空间等。
下面是解决方案:
3.3 线程同步策略
也就是每个线程都进行同步,防止出现线程安全。
3.4. 本地线程分配缓冲
也称TLAB(Thread Local Allocation Buffer),在堆中为每一个线程分配一小块独立的内存,这样以来就不存并发问题了,Java 层面与之对应的是 ThreadLocal 类的实现
4. 初始化
- 分配完内存后要对对象的头(Object Header)进行初始化,这新信息包括:该对象对应类的元数据、该对象的GC代、对象的哈希码。
- 抽象数据类型默认初始化为null,基本数据类型为0,布尔为false。。。
5. 调用对象的初始化方法
也就是执行构造方法。
二、对象的内存模型
头信息
在对象头中有两类信息:标志信息(Mark Word)和类型指针(Kclass Pointer)
1. 标识信息用来存放对象一些固有属性的状态,这些属性从对象创建就有,而不是 Java 的使用者定义的:
* 哈希码:对象的唯一标识符
* 对象的分代年龄:与垃圾回收有关
* 线程持有的锁
* 锁的状态
* 偏向线程 ID、偏向时间戳
* 数组长度:如果该对象是数组,会有数组长度信息
- 类型指针是指向方法区中类元信息的指针。
实例信息(instanceData)
实例的信息存放的是一些对 Java 使用者真正有效的信息,也就是类中定义的各个字段,其中还包括从父类继承的字段。hotspot把相同宽度的类型分配在一起。
内存的对齐填充(Padding)
对其填充这段内存段存在与否取决于前面两部分的长度,为了保证对象内存模型的长度为 8 字节的整数倍,这也是虚拟机自动内存管理的要求(对象起始地址必须是8的整数倍)。
三、对象的访问定位
对象创建起来之后,就会在虚拟机栈中维护一个本地变量表,用于存储基础类型和基础类型的值,引用类型与引用类型的值。
其中引用类型的值就是堆中对象地址。如何引用堆中地址有两种方式:
* 句柄:在堆中维护一个句柄池,句柄中包含了对象地址,当对象改变的时候,只需改变句柄,不需要改变栈中本地变量表的引用
* 直接指针:对象的地址直接存储在栈中,这样做的好处就是访问速度变快(Hotspot采用该方式)

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
JVM内存管理
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36367789/article/details/81605601 关系图: 程序计数器 虚拟机栈 本地方法栈 堆内存 方法区 更深入的了解常量池和intern: JVM将内存主要划分为:方法区、虚拟机栈、本地方法栈、堆、程序计数器。JVM运行时数据区. 关系图: 程序计数器 记录当前线程锁执行的字节码的行号。 1. 程序计数器是一块较小的内存空间。 2. 处于线程独占区。 3. 执行java方法时,它记录正在执行的虚拟机字节码指令地址。执行native方法,它的值为undefined 4. 该区域是唯一一个没有规定任何OutOfMemoryError的区域 虚拟机栈 存放方法运行时所需的数据,成为栈帧。其实它很简单!它里面存放的是一个函数的上下文,具体存放的是执行的函数的一些数据。执行的函数需要的数据无非就是局部变量表(保存函数内部的变量)、操作数栈(执行引擎计算时需要),方法出口等等。 栈帧:执行引擎每调用一个方法时,就为这个函数创建一个栈帧,并加入虚拟机栈。换个角度理解,每个函...
- 下一篇
JVM分析工具概述
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36367789/article/details/81605619 JPS jps jps -q jps -m jps -l jps -v Jstat Jinfo jinfo -flags jinfo -sysprops jinfo -flag -PrintGC jinfo -flag +PrintGC jinfo -flag PrintGC Jmap jmap -finalizerinfo jmap -heap jmap -clstats jmap -histo[:live] jmap -clstats jmap -dump:format=b,file=d:\a.bin pid jmap -histo pid | more Jhat (一般不用,内存占用较高) jhat d:\a.bin oql Jstack jstack jstack -l jstack -m Jconsole 内存监控 线程监控 检查死锁 visualVm JPS java process status 查看进...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2全家桶,快速入门学习开发网站教程
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS8编译安装MySQL8.0.19