深入java虚拟机(二) 对象的创建

java创建对象通常的方式是使用new指令,虚拟机会首先检查new指令的参数(也就是new关键字后面跟着的类名)是否能够在常量池中找到一个类的符号引用,并根据这个符号引用检查其代表的类是否已经加载、解析和初始化,如果没有就先执行类的加载过程。类加载检查后,就会给对象分配内存。新生的对象一般会存在于java堆中,根据java堆的情况,分配内存主要分为两种方式:“指针碰撞”(bump the pointer)和“空闲列表”(free list)。

指针碰撞:假设java堆内存是规整排列的,用过的内存放在一边,空闲的内存放在另一边,中间放着一个指针作为分界指示器,那分配内存操作只是将这个指针往空闲空间那边挪动一段与对象大小相同的距离。

空闲列表:假设java对内存是不规整排列的,虚拟机就需要维护一张空闲内存空间的地址列表,当给对象分配内存时,需要从空闲列表中找到足够的空闲内存空间划分给对象,并且在分配完毕后,还要更新这个空闲地址列表。

选用哪种分配方式取决于java堆内存是否规整,而堆内存是否规整又由虚拟机所采用的垃圾收集器是否带有压缩整理功能所决定。因此, 在使用Serial、ParNew等带有Compact过程的收集器时,系统采用的是指针碰撞,而使用CMS这种基于Mark-Sweep算法的收集器时,系统采用的是空闲列表。

对于创建对象这种频繁操作,虚拟机在分配内存时需要考虑修改指针位置的线程安全问题。解决方案有两种:一种是对分配内存空间的动作进行同步处理——虚拟机采用CAS配上失败重试的方式保证更新操作的原子性;另一种是把内存分配的动作按照线程分配在不同的空间中进行,即每个线程在内存中预先分配一小块内存,成为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB)。哪个线程分配内存,就在哪个线程的TLAB上分配,只有当TLAB用完并分配新的TLAB时,才需要同步锁定。

内存分配完成后,虚拟机将分配的内存空间都初始化为零值(不包括对象头),如果使用TLAB进行分配,则初始化可以提前至TLAB分配时进行。

最后,虚拟机对对象进行必要的设置,包括类的元数据、对象的哈希码、对象的GC分代年龄等信息。这些信息都存放在对象的对象头中,至此,对于虚拟机来说,一个对象的创建过程就结束了。

时间: 2024-08-01 07:14:36

深入java虚拟机(二) 对象的创建的相关文章

Java虚拟机学习-对象的创建

虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载.解析和初始化过.如果没有,必须先执行相应类的加载过程. 类加载检查通过后,接下来虚拟机将为新生对象分配内存.对象所需内存的大小在类加载完成后便可完全确定,为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来.假设Java堆中内存是绝对规整的,所有用过的内存放到一边,空闲的内存放到一边,中间放着指针作为分界点的指示器,那所分配内存仅仅是把那个指针

Java虚拟机学习 - 对象访问

Java虚拟机学习 - 对象访问 分类: JVM2012-09-26 19:36 9280人阅读 评论(17) 收藏 举报 对象访问会涉及到Java栈.Java堆.方法区这三个内存区域. 如下面这句代码: [java] view plaincopyprint? Object objectRef = new Object(); 假设这句代码出现在方法体中,"Object objectRef" 这部分将会反映到Java栈的本地变量中,作为一个reference类型数据出现.而"n

深入理解Java虚拟机(二)、Java对象的创建,内存布局和访问定位

对象的创建: Object obj = new Object(); 常量池中是否有Ljava.lang.Object

虚拟机学习二-对象的创建

对象的创建关注以下几个问题: 1.为创建的对象分配内存空间有两种方式: 指针碰撞: 即规整的划分空间,内存空间中用过的放一边,没用过的放另外一边.需要分配时,指针向空闲空间那边挪动一段与对象大小相等的距离. 空闲列表: 已用和未用空间相互交错,虚拟机需要维护一个列表,记录哪些内存是可以用的,在分配的时候找到一块足够大的给创建的对象实例,并更新列表记录. 2.对象创建在并发情况下不是线程安全的.此时有两种解决方案: -对分配空间的行为进行同步,采用cas配上失败重试的方法保证操作的原子性. -为每

深入理解java虚拟机二,内存管理机制

java 虚拟机自动内存管理. java虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个不同区域 1 程序计数器 每个线程都有一个独立的计数器,用来指示需要执行的字节码的位置. 2 虚拟机栈 虚拟机栈是用来描述java方法执行的内存模型,每个方法被执行的时候都会同时创建一个栈帧用于储存局部变量表,操作栈,动态链接,方法出口等信息. 每一个方法被调用直至执行完成的过程,就对应着一个栈帧从虚拟机栈中从入栈到出栈的过程. 虚拟机栈线程私有,声明周期和线程一样. 局部变量表所需的内存空间在

Java虚拟机二 虚拟机的基本结构

Java虚拟机的基本结构如图所示 类加载子系统负责从文件系统或网络中加载Class信息,加载的类信息存放于一块称为方法区的内存空间.除了类的信息外,方法区中可能还会存放运行是的常量池信息, 包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射). Java堆在虚拟机启动的时候建立,他是Java程序中最主要的内存工作区域.几乎所有的Java对象实例都存放于Java堆中.堆空间是所有的程序共享的. Java的NIO库允许Java程序使用直接内存.直接内存是在Java堆外的

实战java虚拟机(二)——垃圾回收算法

前言 垃圾回收是Java体系最重要的组成部分之一,和C/C++不同,Java虚拟机提供了全自动的内存管理方案,尽量减少了我们在内存资源管理方面的工作量,但是这套方案也并不完美,因此我们也需要深入学习垃圾回收的算法,在工作中遇到内存溢出等问题时也容易更快找到问题所在 一.引用计数法 引用计数法是最古老的垃圾收集算法,它的实现非常简单,只需要为每个对象配备一个整型计数器即可,当对象被引用时,计数器+1,引用失效时计数器-1. 显而易见,这种方式有着两个非常严重的问题: 1.无法处理循环引用,如果对象

深入理解Java虚拟机二之Java内存区域与内存溢出异常

运行时数据区域 1.线程独有的内存区域 PROGRAM COUNTER REGISTER 程序计数器 程序计数器空间较小,是当前线程执行字节码的行号指示器,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令. 如果线程执行的是Java方法,记录的是正在执行的虚拟机字节码指令的地址:如果执行的是Native方法,则为空 VM Stack 虚拟机栈 虚拟机栈生命周期与线程相同.每个Java方法执行时都会创建 原文地址:https://www.cnblogs.com/ggza

Java虚拟机学习--对象实例的创建

1.实例化过程:     在语言层面克隆对象,创建对象,反序列化生成对象都是通过new关键字,虚拟机遇到一条new指令后先检查所实例化的类是否加载(加载后则类存在),是否解析,是否初始化,然后再为新生对象分配内存空间(存放在堆中),设置对象实例的对象头,,将对象体置零,然后执行<init>方法 2.内存分配:GC收集器的算法--->>(是否带有压缩整理功能)GC收集器的种类--->>java堆内存是否规整(规整是指内存是否是由完整的一整块的小块内存组成,比如已经使用过的

Java虚拟机值对象访问以及如何使用对象的引用(2)

对象访问在 Java 语言中无处不在,是最普通的程序行为,但即使是最简单的访问,也会却涉及 Java 栈. Java 堆.方法区这三个最重要内存区域之间的关联关系,如下面的这句代码: Object obj = new Object(); 我们知道在Java栈中保存的是对象的引用,在Java堆中才是具体new出来的对象实体,根据具体类型以及虚拟机实现的对象内存布局( Object Memory Layout)的不同,这块内存的长度是不固定的. 另外,在 Java 堆中还必须包含能查找到此对象类型数