前言
根据之前安排的jvm学习计划在进行jvm学习,找到了尚硅谷宋红康老师的jvm视频,跟着视频学习、做笔记,学习到了很多,为尚硅谷及宋红康老师点赞。说到这里,虽然我有一键三连,但这么好的视频,我又从中受益,心怀感激,放个链接吧:视频传送门
铺垫
前面一直都学得好好的,但是在说到逃逸分析–栈上分配时,宋老师举了一个例子,但是我觉得这个例子不太恰当,但水平有限,不敢贸然点评,所以记下这篇博客,请广大java道友一同讨论,鄙人日后若技术有所精进,也可回头琢磨。
因疑问需要,鄙人根据从《宋老师视频》与《深入理解java虚拟机第二版》中学到的,粗浅的阐述一下逃逸分析,若有不对,还请各位道友指正。
想必广大道友都知道,在jvm的内存模型中, 对象的实体是被存放在堆内存中,而栈中持有的是对象的引用。堆是jvm内存模型中比较大的一块,所以是垃圾回收的重点区域。垃圾回收,就是把那些已经不再“使用”的对象给清理了,给新用到的对象腾出空间嘛。但是呢,对象原本就是用户线程创建的,也是用户线程在使用,所以垃圾回收线程在进行垃圾回收时,无论是判断对象是否在被使用还是对无用对象进行清理,都需要暂停用户线程,待垃圾回收线程将“无用对象”给清理之后,用户线程才可以继续执行自己的业务逻辑。所以呢,垃圾回收并不是越频繁越好,java垃圾回收的初衷是:让java程序员不再去考虑内存管理,一套完善的管理系统肯定要比人手动控制更为准确。但是设计者肯定也不希望因垃圾回收而影响了程序的效率。所以说,如果有更好的,不进行传统的垃圾回收,也能管理内存,那肯定是皆大欢喜的。而逃逸分析–栈上分配就是其中一种比较前沿的这种技术
逃逸分析–栈上分配具体是指什么呢?就是说,如果一个对象,在方法内部被构建,又没有逃逸出方法,那么就可以把这个对象放在栈内存中,随着方法的调用而进栈,创建对象,方法调用结束而出栈,因为对象没有逃出出方法,出栈就可以直接把栈中分配的对象内存给回收了。
上面一段话是我自己理解过后的阐述,来源:
- 宋红康老师的视频:
(宋红康老师逃逸分析视频传送门)
- 深入理解java虚拟机第二版 原文:
疑问
宋红康老师在视频中举的例子如下:
按照送老师的意思,上面那个方法,因为方法返回了在createStringBuffer方法局部创建的StringBuffer对象,所以这个局部创建的StringBuffer对象逃逸了。而下面这个方法,返回的是StringBuffer对象toSring的结果,没有直接返回局部创建的StringBuffer对象,所以没有逃逸。
咋一看,好像是这么回事,但是仔细推敲,发现不太对劲。下面的方法没有直接返回StringBuffer对象的引用,但是别忘了,调用了StringBuffer对的的toString方法,toString作为一个实例方法,可以轻松的拿到这个对象,this就是。虽然我们知道StringBuffer的toString方法没有让this逃逸,但是,jvm在进行逃逸分析的时候,jvm它知道StringBuffer的toString方法有没有让this逃逸吗?
如果说jvm知道,jvm会一层一层的往里面去判断(抛开判断成本),那么,在上面的方法,返回StringBuffer对象的引用,也不能就说发生了逃逸,因为jvm还会去判断调用createStringBuffer方法的方法有没有让这个对象逃逸。
如果说jvm不知道,也就是jvm不会一层一层的往里去判断,那调用了toString方法,也就无法确定toString方法是否有让this逃逸。
所以说,我觉得宋红康老师这个例子不太恰当。
另外,关于jvm会不会一层一层的往里去判断,《深入理解java虚拟机第二版》书中的措辞是:逃逸出方法,并没有详细描述,这个“方法”所代表的含义,所以我也不知道。但是我个人更倾向于,没有一层一层的往里面判断,因为我觉得,一层一层的往里面判断,就相当于最外面这个方法执行了一遍,这成本不是很高吗?