jvm-new个对象

Author Avatar
丁起男 12月 30,2020
  • 在其它设备中阅读本文章

jvm-new个对象

一个java类从编码到最终完成执行,主要包括两个过程:编译、运行

  • 编译:将我们写好的.java文件通过javac命令编译成.class文件
  • 运行:把编译生成的.class文件交由jvm执行

jvm运行class类的时候,并不是一次性将所有的类都加载到内存中,而是用到哪个就加载哪个,并且只加载一次

类的生命周期

加载

加载指的是把class字节码文件从各个来源通过类加载器装载入内存中,这里有两个重点:

  • 字节码来源:一般的加载来源包括从本地路径路径下编译生成的.class文件,从jar包中的.class文件,从远程网络,已经动态代理实时编译
  • 类加载器:一般包括启动类加载器,扩展类加载器,应用类加载器,以及用户的自定义类加载器

验证

主要是为了保证加载进来的字节流符合虚拟机规范,不会造成安全错误。文件格式验证、元数据验证、字节码验证、符号引用验证

准备

给类静态变量分配内存空间,仅仅是分配空间,比如public static int age = 14,在准备后 age = 0,在初始化阶段age = 14,如果添加了final则在这个阶段直接赋值为14

初始化

前面在加载类阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。此时才是真正开始执行类中定义的代码:执行static代码块进行初始化,如果存在父类,先对父类进行初始化

使用

类加载器完毕后紧接着为对象分配内存空间和初始化了:

  • 为对象分配合适大小的内存空间
  • 为实例变量赋默认值
  • 设置对象的头信息,对象hash码、gc分代年龄、元数据信息等
  • 执行构造函数(init)初始化

卸载

通过gc算法回收对象

对象占据字节

一个对象包含三部分

  • 对象头(MarkWord、ClassPointer)
  • 实例数据(InstanceData)
  • 对齐(Padding)

想看内存详细占用清空idea调用jol-core包即可

问题一:new Object()占多少字节

  • markword 8字节 + classpointer 4字节(默认用classPointer压缩)+padding4字节 = 16字节
  • 如果没开启classpointer压缩:markword 8字节 + classpointer 8字节 = 16字节

问题二:User(int id,String name) User u = new User(1,"李四")

markword 8字节 + 开启classPointer压缩后classpointer 4字节 + instancedata int 4字节 + 开启普通对象指针压缩后 String 4字节 + padding 4字节 = 24字节

对象访问方式

使用句柄:使用句柄来访问的最大好处就是reference中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要修改

直接指针:reference 中存储的直接就是对象地址。最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在java中非常频繁,因此这类开销积少成多后也是一项非常可观的执行成本

sun HotSpot使用直接指针访问方式进行对象访问的

原文:https://mp.weixin.qq.com/s/GfAfffbF_uiphN0Zd3YouQ