JVM知识总结(对象)

文章收录在网站:http://hardyfish.top/

文章收录在网站:http://hardyfish.top/

文章收录在网站:http://hardyfish.top/

文章收录在网站:http://hardyfish.top/

对象

对象的生命周期

对象的创建流程:

开始 new一个对象

进行常量池检查

  • 看能否在常量池中定位到这个类的符号引用, 定位不到则加载类
  • 看是否加载过这个类, 没加载过则加载类

分配内存空间

  • 指针碰撞: GC不带压缩功能, Serial和ParNew
  • 空闲列表: GC带压缩功能, CMS

内存空间初始化为零值:

  • 保证了对象的实例字段在不赋初始值就直接使用, 程序能访问到这些字段的数据类型所对应的零值

必要信息设置

  • 对象类的元数据
  • 对象的哈希码
  • GC分代年龄 -> 对象头

init()

一个对象产生到灭亡的过程

新产生的对象优先分配在Eden区。

当Eden区满了或放不下了进行GC,这时候其中存活的对象会复制到From区。

如果From区放不下则会全部进入老年代,然后Eden内存全部清除。

之后产生的对象继续分配在Eden区,当Eden区又满了或放不下了,这时候将会把Eden区和From区存活下来的对象复制到To区。

同理,如果存活下来的对象To区都放不下,则这些存活下来的对象全部进入年老代,之后回收掉Eden区和From区的所有内存。

如上这样,会有很多对象会被复制很多次(每复制一次,对象的年龄就+1),默认情况下,当对象被复制了15次(这个次数可以通过:-XX:MaxTenuringThreshold来配置),就会进入年老代了。

当年老代满了或者存放不下将要进入年老代的存活对象的时候,就会发生一次Full GC(这个是最需要减少的,因为耗时很严重)。

对象的内存分配方式

指针碰撞:

假设堆中的内存是绝对规整的, 所有用过的内存放一边, 未使用内存放另一边, 中间边界线就可以类比为指针, 内存分配就是把指针向未分配的区域挪一段与对象大小相等的距离, 这就是指针碰撞。

空闲列表:

如果堆中的内存不是很规整的, 已使用和未使用的内存就会相互交错, 这个时候就要维护一个列表来记录所有已使用和未使用的内存块, 在分配内存时从列表找到一块足够大的空间划分给对象实例, 并更新内存列表。

分配方法 说明 收集器
指针碰撞 内存地址是连续的(新生代) Serial和 ParNew收集器
空闲列表 内存地址不连续(老年代) CMS收集器和 Mark-Sweep收集器

对象的内存布局

在堆内存中, 一个对象的的存储布局可以分为三个区域:

对象头:

  • 存储对象自身的运行时数据(哈希吗+GC分代年龄+锁状态标准)

  • 类型指针: 类元素的指针, 虚拟机通过这个指针来确定这个对象是哪个类的实例

实例数据:

  • 存储对象真正的有效信息, 例如: 非静态变量也会存入堆空间

对齐填充:

  • JVM内对象都采用8byte对齐, 不够8byte整数倍的就需要通过对齐填充来补全

如何访问一个对象

对象的访问方式由虚拟机决定, 目前主流的访问方式有以下两种

句柄:

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

直接指针:

  • 访问速度快, 节省了一次指针定位的开销
  • 直接访问, reference中存储的就是对象的地址, 节省了一次指针定位的开销

强、软、弱、虚引用

四种引用的目的是让程序自己决定对象的生命周期,通过垃圾回收器对这四种引用做不同的处理,来实现对象生命周期的改变。

强引用:

如果一个对象具有强引用,那垃圾收器绝不会回收它

当内存空间不足,宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用对象来解决内存不足的问题。

如:Object obj = new Object();这种就是强引用。

软引用:

在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行第二次回收。

如果这次回收还没有足够的内存,才会抛出内存溢出异常。

  • 使用软引用的方式是SoftReference。

软引用通常用在对内存敏感的程序中,比如高速缓存就有用到软引用,内存够用的时候就保留,不够用就回收。

弱引用:

在垃圾回收时,如果这个对象只被弱引用关联(没有任何强引用关联他),那么这个对象就会被回收。

  • 只要垃圾回收,不管内存够不够用,弱引用都会被回收。

使用弱引用的方式是类WeakReference。

虚引用:

如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它访问对象,虚引用必须和引用队列(RefenenceQueue)联合使用。

  • 主要作用是跟踪对象垃圾回收的状态。

  • 提供了一种确保对象被 Finalize 以后,做某些事情的机制。

设置虚引用的唯一目的,就是在这个对象被回收器回收的时候收到一个系统通知或者后续添加进一步的处理

相关推荐
程序猿进阶18 分钟前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
阿龟在奔跑12 小时前
引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例
java·jvm·安全·list
王佑辉12 小时前
【jvm】方法区常用参数有哪些
jvm
王佑辉12 小时前
【jvm】HotSpot中方法区的演进
jvm
Domain-zhuo13 小时前
什么是JavaScript原型链?
开发语言·前端·javascript·jvm·ecmascript·原型模式
Theodore_10221 天前
7 设计模式原则之合成复用原则
java·开发语言·jvm·设计模式·java-ee·合成复用原则
我是苏苏1 天前
Web开发:ORM框架之使用Freesql的DbFrist封装常见功能
java·前端·jvm
天草二十六_简村人2 天前
Java语言编程,通过阿里云mongo数据库监控实现数据库的连接池优化
java·jvm·数据库·mongodb·阿里云·微服务·云计算
老码沉思录2 天前
Android开发实战班 - 数据持久化 - Room 数据库应用
android·jvm·数据库
起名字真南2 天前
【C++】深入理解 C++ 中的继承进阶:多继承、菱形继承及其解决方案
java·jvm·c++·chatgpt·aigc