jvm对象分配流程

本文详细解释了垃圾回收器的工作原理,特别是对象内存分配的原则,包括大对象直接进入老年代、长期存活对象晋升、动态年龄调整和内存分配担保。还介绍了TLAB和逃逸分析在对象分配流程中的作用。
摘要由CSDN通过智能技术生成

背景

了解垃圾回收器,除了要知道垃圾回收器的工作原理,我们还要想一个问题,垃圾回收器的垃圾是怎么产生的。所以本期我们讲解一些垃圾回收器的对象内存分配原则。结合这些分配原则,帮助大家在面试时能更好的和面试官吹牛皮。

分配规则

先说一个大的原则,一般的对象会被分配在新生代Eden区,然后经过垃圾回收存活一定时间后进入老年代。这个原则也符合我们的对内存的分带收集理论。但是并不绝对,有一些特例。下面我将讲解这些特例。

大对象直接进入老年代

所谓大对象,就是指很长的字符串或者元素众多的数组。大对象的分配需要连续的内存空间,如果直接分配在新生代,那么在新生代垃圾回收时需要反复的拷贝这个对象,而反复的大内存的拷贝会严重影响GC性能。实际上,垃圾回收过程里,最耗时的就是内存的拷贝过程。所以为了避免这个问题,JVM要求超过一定容量的对象直接分配在老年代,使用参数-XX:PretenureSizeThreshold设置,这个参数的单位是字节数。

长期存活的对象直接进入老年代

当对象经过一定的生存周期,那么对象就可以从新生代晋升为老年代,这个规则是显而易见的,JVM默认是存活15次GC的对象会晋升老念叨。可以使用JVM参数-XX: MaxTenuringThreshold设置。

动态年龄

我们知道JVM是很"聪明"的,能够自适应的调节一些参数。对象晋升老年代也是,如果一次S区中,某个年龄的对象占据S区的一半,那么年龄大于等于该年龄的对象,直接晋升老年代。

内存分配担保

所谓内存担保,是指在老年代预留出内存保证新生代的垃圾回收能够进行。

在发生Minor GC之前,虚拟机会检查老年代最大可用连续空间是否大于新生代所有对象总空间,如果成立,那么Minor GC就是安全的。否则就检查是否允许担保失败,如果允许再检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,则发生Monir GC,如果小于,或者之前设置不允许担保失败,就发生Full GC。

之所以要这么做,是因为存在一种情况,假设Minor GC时,Eden区所有对象都是存活的,需要拷贝到S区,而S区的容量我们知道是不足以容纳Eden区的的,所以需要把对象拷贝到老年代。如果这时老年代没有足够的内存空间,那么本次GC就会失败,所以需要内存分配担保机制。

对象分配流程

了解了上面说的这些规则之后,我们再来看一下一个对象被分配内存的流程是怎样的。先介绍一些需要了解的技术点。

TLAB

全程Thread Local Allocation Buffer,线程如果直接访问堆内存会产生竞争,为了减少竞争,即每个线程私有的一块堆内存,处于新生代。在前面的垃圾回收器章节有介绍。

逃逸分析

逃逸分析是一种编译器的优化技术,简单的说,对象的内存需要在堆内存上分配,但是如果可以将对象的内存分配在栈上,那么就可以省去去堆内存申请的必要。但是栈是很稀有的资源,不能随便分配(至于栈为什么快,其实涉及到操作系统的原理,不是我们了解的重点)。那么那些对象可以分配在栈里呢,就是经过逃逸分析的对象。

逃逸分析的规则是,如果一个对象只在栈内创建,并不会把对象引用传递到栈外,那么对象就可以在栈内创建。简单的说,一个对对象只在方法内部被创建并且使用,而不会传递到方法外部,那么对象就是通过了逃逸分析。

分配流程概述

经过前面的介绍,我们来概括一下对象的分配规则。

对象分配时,先经过编译器的逃逸分析优化,如果对象未逃逸,那么直接分配在栈上。否则,分配在堆上。在分配时,根据对象需要的内存大小判断是不是一个大对象,不是就分配在TLAB里,否则直接进入老年代。因为TLAB是属于新生代的内存区域,当新生代的对象生存一定时间后就进入老年代。当对象使用完毕后就被销毁。

对象分配规则

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值