java中什么是逃逸对象_Java逃逸分析

对象不一定分配在堆上,也可能分配在栈上

[TLAB- Thread-local allocation buffer] 在Java中每个线程都会有自己的缓冲区称作TLAB,每个TLAB都只有一个线程可以操作,TLAB结可以实现快速的对象分配,而不需要任何的锁进行同步,也就是说,在对象分配的时候不用锁住整个堆,而只需要在自己的缓冲区分配即可。

[方法逃逸] 当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中,我们称为方法逃逸。

sb是一个方法内部变量,上述代码中直接将sb返回,这样这个StringBuilder有可能被其他方法所改变,这样它的作用域就不只是在方法内部,虽然它是一个局部变量,称其逃逸到了方法外部。

甚至还有可能被外部线程访问到,譬如赋值给类变量或可以在其他线程中访问的实例变量,称为线程逃逸。

上述代码如果想要sb不逃出方法,可以这样写:

不直接返回 StringBuilder,那么StringBuilder将不会逃逸出方法。

经过逃逸分析之后,可以得到对象三种可能的逃逸状态:

1. GlobalEscape(全局逃逸): 即一个对象的引用逃出了方法或者线程。例如,一个对象的引用是复制给了一个类变量,或者存储在在一个已经逃逸的对象当中,或者这个对象的引用作为方法的返回值返回给了调用方法。

2. ArgEscape(参数级逃逸):即在方法调用过程当中传递对象的应用给一个方法。这种状态可以通过分析被调方法的二进制代码确定。

3. NoEscape(没有逃逸):如果能证明一个对象不会逃逸到方法或线程外(只会在一个方法/线程中用到),则可能为这个变量进行一些高效的优化:

1) 栈上分配:我们都知道Java中的对象都是在堆上分配的,而垃圾回收机制会回收堆中不再使用的对象。但是筛选可回收对象,回收对象还有整理内存都需要消耗时间。如果能够通过逃逸分析确定某些对象不会逃出方法之外,那就可以让这个对象在栈上分配内存,这样该对象所占用的内存空间就可以随栈帧出栈而销毁,就减轻了垃圾回收的压力。在一般应用中,如果不会逃逸的局部对象所占的比例很大,如果能使用栈上分配,那大量的对象就会随着方法的结束而自动销毁了。

2) 锁消除:线程同步的代价是相当高的,同步的后果是降低并发性和性能。逃逸分析可以判断出某个对象是否始终只被一个线程访问,如果只被一个线程访问,那么对该对象的同步操作就可以转化成没有同步保护的操作,这样就能大大提高并发程度和性能。

3) 标量替代:如果把一个Java对象拆散,用其成员变量(分散的标量)代替该对象整体,从而不需要连续的存储空间,就可以将对象的部分甚至全部都保存在CPU寄存器内,这样能大大提高访问速度。

[jvm参数(VM option)]

-XX:+DoEscapeAnalysis(开启逃逸分析)

-XX:+DoEscapeAnalysis -XX:+EliminateAllocations(开启标量替换必须开启逃逸分析)

-XX:+DoEscapeAnalysis -XX:+EliminateLocks(开启锁消除必须开启逃逸分析)

//非逃逸分析优化手段,但也是通过分析作用域来提供内部锁的性能:

a) 锁粗化:当连续获取同一个对象的锁时,HotSpot虚拟机会去检查多个锁区域是否能合并成一个更大的锁区域。这种聚合被称作锁粗化,它能够减少加锁和解锁的消耗。

b) 嵌套锁:同步块可能会一个嵌套一个,进而两个块使用同一个对象的监视器锁来进行同步也是很有可能的。这种情况我们称之为嵌套锁,HotSpot虚拟机是可以识别出来并删除掉内部块中的锁的。当一个线程进入外部块时就已经获取到锁了,因此当它尝试进入内部块时,肯定也仍持有这个锁,所以这个时候删除锁是可行的。

//锁粗化:

//嵌套锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值