Java对象与JVM(一)  Java对象在Java虚拟机中的创建过程_java撖寡情 jvm-程序员宅基地

技术标签: 后台  

 

 

       在《Java内存区域 JVM运行时数据区》文章了解到Java中几乎所有的实例对象存储在Java堆内存中。

       下面我们详细了解Java程序中new一个普通对象时,HotSpot虚拟机是怎么样创建这个对象的,包括5个步骤:相应类加载检查过程、在Java堆中为对象分配内存、分配后内存初始化为零、对对象进行必要的设置、以及执行对象实例方法<init>,最后我们再从JVM指令角度来解释下Java对象创建。

1、相应类加载检查过程

       通过《JVM字节码指令及反编译分析》可以知道:Java程序中的“new”操作会转换为Class文件中方法的“new”字节码指令。

       JVM(本文特指HotSpot)遇到new指令时,先检查指令参数是否能在常量池中定位到一个类的符号引用:

       (A)、如果能定位到,检查这个符号引用代表的类是否已被加载、解析和初始化过;

       (B)、如果不能定位到,或没有检查到,就先执行相应的类加载过程;

2、为对象分配内存

      对象所需内存的大小在类加载完成后便完全确定(JVM可以通过普通Java对象的类元数据信息确定对象大小);

      为对象分配内存相当于把一块确定大小的内存从Java堆里划分出来;

(A)、分配方式:

(I)、指针碰撞

      如果Java堆是绝对规整的:一边是用过的内存,一边是空闲的内存,中间一个指针作为边界指示器;

      分配内存只需向空闲那边移动指针,这种分配方式称为"指针碰撞"(Bump the Pointer);

(II)、空闲列表

      如果Java堆不是规整的:用过的和空闲的内存相互交错;

      需要维护一个列表,记录哪些内存可用;

      分配内存时查表找到一个足够大的内存,并更新列表,这种分配方式称为"空闲列表"(Free List);

      Java堆是否规整由JVM采用的垃圾收集器是否带有压缩功能决定的;

      所以,使用Serial、ParNew等带Compact过程的收集器时,JVM采用指针碰撞方式分配内存;而使用CMS这种基于标记-清除(Mark-Sweep)算法的收集器时,采用空闲列表方式;

      后面再介绍垃圾收集算法和垃圾收集器,了解垃圾收集时应注意这里的内容;

(B)、线程安全问题

      并发时,上面两种方式分配内存的操作都不是线程安全的,有两种解决方案:

(I)、同步处理

      对分配内存的动作进行同步处理:

      JVM采用CAS(Compare and Swap)机制加上失败重试的方式,保证更新操作的原子性;

      CAS:有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做;

(II)、本地线程分配缓冲区

      把分配内存的动作按照线程划分在不同的空间中进行:

      在每个线程在Java堆预先分配一小块内存,称为本地线程分配缓冲区(Thread Local Allocation Buffer,TLAB);

      哪个线程需要分配内存就从哪个线程的TLAB上分配;

      只有TLAB用完需要分配新的TLAB时,才需要同步处理;

JVM通过"-XX:+/-UseTLAB"指定是否使用TLAB;

3、对象内存初始化为零

      对象内存初始化为零,但不包括对象头;

      如果使用TLAB,提前至分配TLAB时;

      这保证了程序中对象(及实例变量)不显式初始赋零值,程序也能访问到零值;

4、对象内存初始化为零

      主要设置对象头信息,包括类元数据引用、对象的哈希码、对象的GC分代年龄等(详见下节);

5、执行对象实例方法<init>

      该方法把对象(实例变量)按照程序中定义的初始赋值进行初始化;

        

      通常,经过上面5步对象才完全new出来。

      另外,还可以参考HotSpot虚拟机源码中的"bytecodeInterpreter.cpp"文件,这个文件有表示解释器处理"new"指令基本类似上面的5个过程。

6、Java对象创建的JVM指令

      通过前面一些文章,我们还可以从JVM指令的角度来看对象的创建过程:

(A)、new指令

      "new"指令有一个类符号引用的常量,JVM解析该常量也就对应步骤1"相应类加载检查过程";

      "new"指令执行完毕后,一个代表(指向)该对象实例内存数据的reference类型变量数据将压入到操作数栈中

(B)、dup指令

      接着会执行"dup"指令复制该reference数据,这时操作数栈栈顶就有两个指向该对象实例内存的reference数据;(如果<init>方法有参数,还需要把参数加载到操作栈

(C)、invokespecial指令

      再执行"invokespecial"指令调用对象实例方法<init>,这时操作数栈最上面的一个reference数据会出栈(如果有参数,包括方法参数);

      然后在Java虚拟机栈中创建<init>方法的栈帧,把出栈的reference数据(和参数)放入该栈帧的局部变量表中,该reference数据在方法中也就是"this",表示对该对象实例进行的操作

      当然这些参数的数值、数据类型和顺序都必须遵循实例方法的描述符中的描述;

      另外,操作数栈中还有一个对象reference数据一般被“astore”到局部变量表或保存到字段变量,给后面访问对象使用。

 

      到这里,我们大体了解Java对象在HotSpot虚拟机中的创建过程, 后面我们将分别去了解:对象的内存布局、对象的访问定位、方法的调用与执行、JIT编译、以及JVM垃圾收集相关内容……

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_38384440/article/details/81662101

智能推荐

promise解决重复调用同一接口(同步)_promise.all并行调同一个接口-程序员宅基地

文章浏览阅读4.7k次。前端实现多次调用同一个接口,所有数据均成功返回后,才可继续执行下面的代码封装请求数据方法getData(param) { return new Promise((resolve, reject) => { this.$axios .get(`/xx/xx/xxpath/${param}`) .then(res => { let content = res.data reso_promise.all并行调同一个接口

socket编程种名字与地址转换函数_getservbyname是可重入函数吗-程序员宅基地

文章浏览阅读274次。参考:《UNIX 网络编程 · 卷1 : 套接字联网API》之前都是使用数值地址来表示主机(比如:127.0.0.1),用数值端口号来标识服务器(比如:6379)。但是有时候最好使用名字而不是数值:名字比较容易记住,数值地址容易变动,而名字地址保持不变;随着 IPv6 上转移,数值地址变得很长,手工键入数值容易出错。之后将有一系列函数用于名字、数值、端口之间的转换。gethostbyname & gethostbyaddr 函数gethostbyname 函数查找主机名字最基本的函数时 g_getservbyname是可重入函数吗

第一章 Java概述_第 1章java me的概述-程序员宅基地

文章浏览阅读436次。JavaSE结构•Java概述•Java编程基础•面向对象编程•异常处理•API常用类•多线程•容器类•I/O•网络编程•注解1 Java概述结构•1.1 软件编程常识•1.2 Java语言概述•1.3 Java体系结构•1.4 Java语言的跨平台特性•1.5 搭建Java程序的开发环境•1.6 Java程序开发体验_第 1章java me的概述

CSS 选取第几个标签元素_css 第几个几个div-程序员宅基地

文章浏览阅读1w次,点赞6次,收藏11次。在前端开发中,我们可能会碰到这样的需求:想让列表中的第一个部分显示不同的样式 ,想让列表中的偶数部分显示不同的背景颜色,想让列表中的最后一部分样式不一样……这样的需求,我们怎样来实现?其实,如果前面文件是php开发的,可以通过php的循环语句+判断语句+css样式来实现。但是,如果是静态代码,php就无法用了。这时,我们还可以通过CSS来实现,CSS给我们提供了几个非常有用的样式参数:first-..._css 第几个几个div

固定资产管理系统的打造-程序员宅基地

文章浏览阅读106次。固定资产管理总体分为两个部分:固定资产管理财务帐部分,固定资产管理实物帐部分。前者偏重价值管理,后者偏重实物管理,前者一般由财务部门负责,后者一般由行政部门负责。两部分信息又是紧密衔接相辅相成的,通过信息系统的..._crv管理系统

SAP MM 物料主数据MRP2 视图Rounding Value字段-程序员宅基地

文章浏览阅读639次。SAP MM 物料主数据MRP2 视图Rounding Value字段如下物料号,MRP2视图中,维护了rounding value字段值为50。MRP type..._sap mpr2视图

随便推点

单片机入门资料,按键消抖方式,按键怎么消抖_单片机按键消抖-程序员宅基地

文章浏览阅读1.2w次,点赞19次,收藏108次。1.什么是按键消我们先来看一下按键按下去的波形图1.按键消抖原理我们可以看到当按键按下的那一时刻和松开的时候有类似于锯齿的形状那就是按键抖动,这个抖动不是我们人为能控制得了的,所以我们只能对进行硬件消抖或者进行软件消抖本期我们讲解软件消抖.**上图中我们可以看到理想波形和实际波形有很大的区别,区别在于实际波形在按键按下的那一刻前后有20毫秒的抖动,我们按键消抖的目的呢就是把抖动忽略掉只要中间的稳定闭合区域.**## 方法一延时消抖法可以用延时的方式跳过抖动的区域优缺点:优点._单片机按键消抖

Image2Lcd图片取模软件-程序员宅基地

文章浏览阅读3.7w次,点赞73次,收藏265次。image2lcd是一款非常简单使用的图片转换成LCD图像数据的图片转换软件。它能够将各种形式来源的图片转换成特定的数据格式以用来匹配单片机系统所需要的显示数据格式。在输入方面,它支持JPG、BMP、EMF、WBMP、GIF、ICO等多种格式图片的输入,输出的数据拥有二进制类型、WBMP格式、C语言数组类型和标准的BMP格式等多种类型。同时它还能将图象的数据扫描方式、亮度、对比度、灰度(颜色数)以及图像数据排列方式等等进行调节。image2lcd v3.2破解版image2lcd是一款非常简单使_image2lcd

IOS里的TaggedPointer[NSNumber篇]_nsnumber的tagged pointer-程序员宅基地

文章浏览阅读1.9k次。转自:http://www.infoq.com/cn/articles/deep-understanding-of-tagged-pointer/前言在2013年9月,苹果推出了iPhone5s,与此同时,iPhone5s配备了首个采用64位架构的A7双核处理器,为了节省内存和提高执行效率,苹果提出了Tagged Pointer的概念。对于64位程序,引入Tagged Po_nsnumber的tagged pointer

BUUCTF_2.RIP覆盖一下_buuctf rip-程序员宅基地

文章浏览阅读3.7k次。解题思路1. 查看文件信息,安全机制2. 代码审计3. 分析漏洞点4. 编写EXP1.基本信息$checksec ./文件名2.代码审计不管在简单题都一定要IDA查看一下伪代码(IDA做好是7.0以上的版本)首先查看敏感字符串(Ctrl+1)1.gets从标准输入设备读字符串函数,其可以无限读取,不会判断上限,以回车结束读取,所以应该确保buffer的空间足够大,以便在执..._buuctf rip

curl_init()和curl_multi_init()多线程的速度比较_curl_multi_init c++-程序员宅基地

文章浏览阅读7k次。php中curl_init()的作用很大,尤其是在抓取网页内容或文件信息的时候,例如之前文章curl获得header检测GZip压缩的源代码就介绍到curl_init()的强大。curl_init()处理事物是单线程模式,如果需要对事务处理走多线程模式,那么php里提供了一个函数curl_multi_init()给我们,这就是多线程模式处理事务的函数。curl_init()与cur_curl_multi_init c++

execve系统调用_execve系统调用寄存器参数-程序员宅基地

文章浏览阅读2.6k次。sys_execve()在真正的开始执行系统调用函数之前,系统调用服务程序已经将一些系统调用的函数的参数传递给了相应的寄存器,比如这里的ebx,ecx,edx都分别保存了系统调用的参数,ebx保存的是第一个参数,依次类推(当然最多传递的参数个数不能大于5个),首先这个函数通过ebx获取需要执行的文件的绝对路径,他通过这样一个函数实现获取到文件名之后他就会调用do_execve();_execve系统调用寄存器参数

推荐文章

热门文章

相关标签