JVM【第四回】:【对象访问】

介绍完Java虚拟机的运行时数据区后,我们就可以探讨在Java语言中,对象访问是如何进行的?如下面这句代码:

Object obj = new Object();

假设这句代码出现在方法体中,那“Object obj”这部分的语义将会反映到Java栈的本地变量表中,作为一个reference类型数据出现。而“new Object()”这部分的语义将会反映到Java堆中,形成一块存储了Object类型所有实例数据值的结构化内存,根据具体类型以及虚拟机实现的对象内存布局的不同,这块内存的长度是不固定的。另外,在Java堆中还必须包含能查找到此对象类型数据(如对象类型、父类、实现的接口、方法等)的地址信息,这些类型数据则存储在方法区中。

由于reference类型在Java虚拟机规范中里面只规定了一个指向对象的引用,并没有定义这个引用应该通过哪种方式去定位,以及访问到Java堆中的对象的具体位置,因此不同的虚拟机实现的对象访问方式会有所不同,主流的访问方式有两种:使用句柄和直接指针。

  • 如果使用句柄访问方式,Java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对

象实例数据和类型数据各自的具体地址信息,如下图所示:

  • 如果使用直接指针访问方式,Java堆对象的布局中就必须考虑如何放置访问类型数据信息,reference中直接存储的就是对象地址,

如下图所示:

这两种对象的访问方式各有优势,使用句柄访问方式的最大好处就是reference中存的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时之改变句柄中的实例数据指针,而reference本身不需要被修改。

使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在Java中非常频繁,因此这类开销积少成多后也是一项非常客观的执行成本。Sun HotSpot采用的第二种方式进行对象访问的。

欲知后事如何,且听下回分解

时间: 2024-10-07 15:34:29

JVM【第四回】:【对象访问】的相关文章

JVM【第十四回】:【回收方法区】

很多人认为方法区(或者HotSpot虚拟机中的永久代)是没有垃圾收集的,Java虚拟机规范中确实说过可以不要求虚拟机在方法区实现垃圾手机,而且在方法区进行垃圾收集的"性价比"一般比较低:在堆中,尤其是在新生代中,常规应用进行一次垃圾收集一般可以回收70%~90%的空间,而永久代的垃圾收集效率远低于此. 永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类.回收废弃常量与回收Java堆中的对象非常类似.以常量池中字面量的回收为例,假如一个字符串"abc"已经进入了常

四、对象如何创建,布局?如何访问数据

四.对象如何创建,布局?如何访问数据 对象的内存分配 对象的创建过程 Jvm读到new指令, 先去方法区(类常量池中)查看是否有对应的类符号,并检查该类是否被加载, if 加载,JVM为新生对象分配内存 else 加载类,为对象分配内存 内存分配完,JVM将内存空间值初始化为0值 对象头信息记录,这个对象是哪个类的实例,如何找到类元数据信息,对象哈希码值,对象的GC分代信息记录到对象头中: new之后执行init操作 JVM内存分配的方式 指针碰撞Bump the pointer分配内存 如果堆

【深入理解JVM】:Java对象的创建、内存布局、访问定位

对象的创建 一个简单的创建对象语句Clazz instance = new Clazz();包含的主要过程包括了类加载检查.对象分配内存.并发处理.内存空间初始化.对象设置.执行ini方法等. 主要流程如下: 1. 类加载检查 JVM遇到一条new指令时,首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那必须先执行相应的类的加载过程. 2. 对象分配内存 对象所需内存的大小在类加载完成后便完全确定(对象内存布局),

JVM总括四-类加载过程、双亲委派模型、对象实例化

JVM总括四-类加载过程.双亲委派模型.对象实例化 一. 类加载过程 一定要注意每个过程执行的内容!!!!!! 1.Load: 将编译后的.class文件以二进制流的方式加载到JVM内存中,并转化为特定的数据结构,用到的就是classLoad二类加载器.这个过程中校验cafe babe魔法数.常量池.文件长度.是否有父类等. 2.Link: 分为验证.准备.解析三步. 验证:更为详细的验证,比如:final是否规范(二次赋值不规范).static是否合理(静态方法必须引用静态变量).类型是否正确

设计模式(2)_代理模式 ————— 控制对象访问

设计模式(2)_代理模式 ----- 控制对象访问 一.动机 需求 现在有这样一个需求:有一个出版社,该出版社有一个工厂,专门用来生产制造图书,该工厂里有很多台生产制造图书的机器.每个机器有自己的位置坐标,用 int表示,机器的状态,{正在工作,暂停,故障},已经印刷了多少页图书.在出版社 在工厂 厂长的电脑屏幕上,可以随时打印出任何一台机器的报告信息(report infomation). 下来 我们用代码实现这个需求: PrinterMachine.java package com.crg;

深入JVM虚拟机(四) Java GC收集器

深入JVM虚拟机(四) Java GC收集器 1 GC收集器 1.1 Serial串行收集器 串行收集器主要有两个特点:第一,它仅仅使用单线程进行垃圾回收:第二,它独占式的垃圾回收. 在串行收集器进行垃圾回收时,Java 应用程序中的线程都需要暂停("StopThe World"),等待垃圾回收的完成,这样给用户体验造成较差效果.虽然如此,串行收集器却是一个成熟.经过长时间生产环境考验的极为高效的收集器.新生代串行处理器使用复制算法,实现相对简单,逻辑处理特别高效,且没有线程切换的开销

httpClient Post例子,Http 四种请求访问代码 HttpGet HttpPost HttpPut HttpDelete

httpclient post方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //----1. HttpPost request = new HttpPost(url); // 先封装一个 JSON 对象 JSONObject param = new JSONObject(); param.put("name", "rarnu"); param.put("password", "123456"

面向对象的类访问和对象访问的区别【this以及类访问】、静态成员的访问区别、类常量等、继承和重写、访问修饰限定符、冒泡排序

1.mysql封装类 在构造函数中定义初始化数据库连接的相关参数[因为实例化对象时传入的参数是该对象的唯一参数入口]但是不需要再构造函数中进行冗余定义,而是在构造函数中进行调用类中的其他方法的方式来实现构造函数的设置工作[这样的模块分离使逻辑更加简单] [重点]2.静态成员相当于每次实例化对象之间是有关系的[例如计数功能]因为每次实例化类时创建的对象占用的空间都是新创建的,这一点需要注意,所以同一个类下的对象之间的变量并没有交互的效果.[回想起当初函数中的静态局部变量的使用][延生到静态全局变量

jvm如何知道那些对象需要回收

1 首先的问题是:jvm如何知道那些对象需要回收 ? 目前有两种算法 引用计数法 每个对象上都有一个引用计数,对象每被引用一次,引用计数器就+1,对象引用被释放,引用计数器-1,直到对象的引用计数为0,对象就标识可以回收 这个可以用数据算法中的图形表示,对象A-对象B-对象C 都有引用,所以不会被回收,对象B由于没有被引用,没有路径可以达到对象B,对象B的引用计数就就是0,对象B就会被回收. root搜索算法 这种算法目前定义了几个root,也就是这几个对象是jvm虚拟机不会被回收的对象,所以这