将弱引用传入inline函数会发生内存泄漏


#1

错误描述:

测试代码很简单,如下,用弱引用持有"any"对象,每隔一秒调用测试函数,并查看"any"对象是否释放。
始料未及的是,为测试函数加上“inline”后,"any"对象一直不会释放

class KotlinTest {

//使用 inline符 参数block会被铺平,相当于外部直接调用 toString()
inline fun inlineFun(block: () -> Any?) {
	block().toString()
}

//不使用 inline符 参数block将被执行,取得结果后再调用 toString()
fun normalFun(block: () -> Any?) {
	block().toString()
}

//调用此方法进行测试,用AndroidStudio的Profiler工具主动回收内存来测试泄漏
//因"用main函数运行"和"用手机运行"的测试结果不同,所以统一用手机测试为准
fun 测试内存回收() {
	object : Thread() {
		override fun run() {
			var any: File? = File("C:/123")
			val weakRef = WeakReference(any)

			//每隔1秒,调用测试方法,并查看是否释放
			while (true) {
				Thread.sleep(1000)
				//TODO 调用测试函数,修改此行代码来更换测试函数
				normalFun { "" + weakRef.get() }

				System.out.println("弱引用持有=${weakRef.get()}")
				System.out.println("any=$any")
				any = null
			}
		}
	}.start()
}

}

小米9运行结果:

当block的内容是 weakRef.get() 时:
·调用"inlineFun()"或"normalFun()"都不影响"any"对象释放
但当block的内容是 “” + weakRef.get() 时:
·调用"normalFun()"时对象正常释放
·调用"inlineFun()"时"any"对象却始终不释放

更为神奇的是,若 inlineFun() 中的代码实际未执行,如下,那么"any"对象能正常释放
inline fun inlineFun(block: () -> Any?) {
if (System.currentTimeMillis() < 0)
block().toString()
}

难道我们以后都要注意别把弱引用传入inline函数里吗
求大佬解答为何出现这一现象


#2

你要了解一下 inline 实际上是把函数的代码展开,因此这里 “” + weakRef.get() 会被展开到 while 循环当中。而由于这里产生了字符串的拼接,因此目测 weakRef.get() 的结果应该会被压栈,只有当所在的 run 方法退出才会释放。

说到底,跟 inline 函数没什么关系,正常也不会写出死循环吧。


京ICP备16022265号-2 Kotlin China 2017 - 2018