引言

  Java程序员都知道如何创建对象,不就是一个Person person = new Person()的语句就解决了么?然而,我们只知道new,却对于底层如何实现对象的创建、如何存储到内存中去、又如何被访问的知之甚少。

对象的创建

流程图

对象创建流程图

创建流程

  1. Java程序new一个对象。
  2. 虚拟机遇到一条new指令时,首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,且检查该符号引用代表的类是否已被加载、解析和初始化过。若没有,需先进行相应的类加载过程。
  3. 在类加载检查通过后,虚拟机将为新生对象分配内存。(对象在内存中所需要的大小在类加载完成后就确定了)
  4. 内存分配完之后,虚拟机需要将分配到的内存空间初始化为零值(不包括对象头)。保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,可以访问对应的零值。(对应准备阶段)
  5. 虚拟机对对象进行必要的设置(对象头的设置)。如这个对象是哪个类的实例、如何找到类的元数据信息、对象哈希码、对象的GC分代年龄等信息。
  6. 以上虚拟机中新对象产生,对应到Java程序还需要继续执行方法,将对象在程序中进行初始化。

内存空间分配方式

  为对象分配空间就是从Java堆中划分出一块确定大小的内存给新生对象,考虑符合划分可用空间的两种方式:“指针碰撞”和“空闲列表”

  • 指针碰撞:若Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,所分配内存仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离。在使用Serial、ParNew收集器时等带有Compact过程时,系统分配算法是指针碰撞。
  • 空闲列表:Java堆中内存不是规整的,已使用的内存和空闲的内存相互交错,VM需维护一个列表,记录上哪些内存是可用的,在分配时从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录。使用CMS收集器时,就是采用的空闲里列表,CMS是基于Mark-Sweep算法(标记-清除)的收集器。

并发安全问题

  Java对象创建在程序中是非常常见的,所以在VM中对象创建是非常频繁,容易出现多线程并发安全问题:如程序中创建对象A和对象B,底层VM给A对象分配内存,指针没来及修改,对象B同时使用原来的指针分配内存。  解决方案有两种:同步处理和本地线程分配缓冲

  • 同步处理:分配内存空间的动作进行同步处理(CAS操作),VM采用CAS配上失败重试的方式保证更新操作的原子性
  • 本地线程分配缓冲:Thread Local Allocation Buffer, TLAB,把内存分配的动作按照线程划分不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,即为TLAB,哪个线程要分配内存,就在哪个线程的TLAB上分配,只有用完后并分配新的TLAB,才需要同步锁定。通过-XX:+/-UseTLAB参数设定是否需要使用TLAB。

对象的内存布局

概述

  Java对象在内存存储的布局分为3块:对象头、实例数据和对齐填充

对象头

  对象头(Header)分为两部分:用于存储对象自身的运行时数据和类型指针

运行时数据

  Mark Word,用于存储对象自身的运行时数据包括:哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。

存储内容 标志位 状态
对象哈希码、GC分代年龄 01 未锁定
指向锁记录的指针 00 轻量级锁定
指向重量级的指针 10 膨胀(重量级锁定)
空,不需要记录信息 11 GC标志
偏向线程ID、偏向时间戳、对象分代年龄 01 可偏向

  Mark Word是一个非固定的数据结构,在极小的空间内存储尽量多的数据,会根据对象的状态复用自己的存储空间,如在32位HotSpot VM中,若对象处于未锁定状态,Mark Word的32bit空间中25bit用于存储对象哈希码,4bit用于存储对象分代年龄,2bit用于存储锁标志位,1bit固定为0,即32(存储空间)=25(哈希码)+4(分代年龄)+2(锁标志位)+1(固定0)

类型指针

  即对象指向它的类元数据的指针,虚拟机通过这个指针来确定对象是哪个类的实例,但是并非查找对象的元数据就一定要通过对象本身,也只是适用于普通对象,普通Java对象可以通过元数据信息可以确定Java对象的大小。不适用的Java对象,如Java数组对象的对象头中必须有一块能保持记录数组长度的数据,因为从数组元数据中无法确定数组的大小。

实例数据

  实例数据(Instance Data)是对象真正存储的有效信息,也是程序代码中定义的各种类型的字段内容。这部分存储顺序会受到VM分配策略参数字段在Java源码中定义顺序的影响。VM默认分配策略
  HotSpot默认分配策略为longs/doubles、ints、shorts/chars、bytes/nooleans、oops,相同宽度的字段会被分配到一起,在父类中定义的变量会出现在子类之前。

对齐填充

  对齐填充(Padding)是非必要的,只是起着占位符的作用。VM自动内存管理系统要求对象起始地址(对象大小)必须是8字节的整数倍,对象头都是8字节的整数倍,而实例数据部分若没有8字节的整数倍,可以通过对齐填充进行补全。

对象的访问方式

概述

  Java程序通过栈上的reference数据类操作堆上的具体对象(栈中的局部变量表存储了对象名的变量,堆中存储了对象的具体地址)。主流的对象访问定位方式有两种:使用句柄和直接指针

使用句柄

  使用句柄访问对象,Java堆中会划分出一块内存作为句柄池reference中存储的就是对象的句柄地址,句柄中包含了对象实例数据与类型数据各自的具体地址信息。

直接指针

  使用直接指针访问,Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址。(Sun HotSport VM的使用方式)

访问方式对比

  使用句柄访问优势是reference中存储的是稳定的句柄地址,对象被移动时,只会改变句柄中实例数据指针,reference本身不会变;
  使用直接指针访问优势是速度快,节省一次指针定位时间开销。(JVM默认使用)

参考
《深入理解Java虚拟机》

【其他JVM学习链接】

七大GC器

JMM内存模型

JVM类加载过程

[每篇微语]

当一个人一心一意做好事情的时候,他最终是必然会成功的。

—— 卢梭

sqlserver2008未将对象引用设置到对象的实例_JVM | Java对象的创建、存储和访问详解...相关推荐

  1. sqlserver2008未将对象引用设置到对象的实例_面试官:ThreadLocal 的内存泄漏是弱引用导致的,你确定?...

    面试官:ThreadLocal 了解吗? Python 小星:线程局部变量,多线程下能保证各个线程的变量相对独立于其他线程的变量. 面试官:那你说下它是如何保证线程隔离的? Python 小星:每个线 ...

  2. 未将对象引用设置到对象的实例--可能出现的问题总结

    一.网络上的一般说法 1.ViewState 对象为Null. 2.DateSet 空. 3.sql语句或Datebase的原因导致DataReader空. 4.声明字符串变量时未赋空值就应用变量. ...

  3. c#_未将对象引用设置到对象的实例

    一开始学习C#的时候用用户控件,但是控件经常崩溃,有时一旦崩溃几乎无解,所以经过半年时间,我们老师决定让我们放弃使用用户控件. 不知道你们有没有遇到过类似的情况,在用户控件里一顿撤销之后发现程序崩了, ...

  4. c#:未将对象引用设置到对象的实例--可能出现的问题总结(转)

    摘自:http://blog.csdn.net/sollion/article/details/5777475 一.网络上的一般说法 1.ViewState 对象为Null. 2.DateSet 空. ...

  5. 未将对象引用设置到对象的实例

    未将对象引用设置到对象的实例 在这个项目中,就是空指针异常. string web_response = "{}";JObject jo;try {jo = JObject.Par ...

  6. 浅说--未将对象引用设置到对象的实例(System.NullReferenceException)

    System.NullReferenceException:未将对象引用设置到对象的实例,这是一个新鸟,中鸟,老鸟都避不开的错误. 下面基础的解释一下这错误:   1:本质上的错误:   object ...

  7. C#学习Error问题:“System.NullReferenceException:未将对象引用设置到对象的实例”

    [问题描述] 问题报错提示:"System.NullReferenceException:未将对象引用设置到对象的实例" 详细信息: System.NullReferenceExc ...

  8. vs2013 未将对象引用设置到对象的实例

    在一些特殊情况发生后,vs会出现无法复制粘贴,使用快捷键则会出现 未将对象引用设置到对象的实例 的弹窗,使用起来很不方便. 经过探索,一个博友的回答解决了我的问题,直接删除 C:\Users\Admi ...

  9. 如何在ashx页面获取Session值(未将对象引用设置到对象的实例) (转)

    如何在ashx页面获取Session值(未将对象引用设置到对象的实例) 分类: .Net学习笔记 Session 2011-11-30 10:25 902人阅读 评论(1) 收藏 举报 在一般事务处理 ...

最新文章

  1. Linux火狐解压完运行不了,在Ubuntu系统下firefox账号无法登录的解决
  2. 剑指offer之41-45题解
  3. Sqlserver 数据库安全
  4. 换行符‘\n’和回车符‘\r’
  5. jqGrid获取数据库数据的方式
  6. EditRocket for Mac(源代码编辑器)v4.5.10
  7. openfire 详细介绍一
  8. PyTorch报错:xxx.pth is a zip archive(did you mean to use torch.jit.load()?)
  9. 利用lcx作端口映射
  10. html+css制作静态小米商城页面(含css手动轮播图)
  11. java 限流器实现
  12. 10 道 OOP 方面的 Java 面试题,祝你跳槽涨薪一臂之力
  13. 疯狂值班表(人员跟日期生成的视图)
  14. Qt+ECharts开发笔记(五):ECharts的动态排序柱状图介绍、基础使用和Qt封装Demo
  15. 【免费分享】[艾略特波浪理论-20周年纪念版]
  16. CNN FPGA加速器实现(小型)CNN FPGA加速器实现(小型)
  17. 考前必看!你需要知道的英语六级秘笈
  18. 前端导出文件 前端导出excel表格 下载文件
  19. Scratch基础(九):动画-宇宙遨游
  20. 7-55 查询水果价格 (15 分) 给定四种水果,分别是苹果(apple)、梨(pear)、桔子(orange)、葡萄…PTA:中M2021春C、Java入门练习第I段——变量、表达式、分支、循环

热门文章

  1. Oracle expdp 导出
  2. 【转】MS-DOS下怎样使用解压缩共具
  3. C#仿QQ皮肤-ContextMenuStrip 控件实现
  4. iterator遍历_HashMap 的 7 种遍历方式与性能分析!(强烈推荐)
  5. QT接收Linux内核,QT界面程序经过网路与普通的linux应用程序进行数据传送的情况...
  6. 深度剖析python_汉诺塔问题深度剖析(python实现)
  7. 图标,专业设计师基本素材要件
  8. 清新手绘水果平面设计|面膜的包装设计越来越精致了!
  9. 超经典实用APP UI产品界面设计模板
  10. 实物贴图风格拟物图标素材,高逼格即显