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使用直接指针访问方式进行对象访问的