Ely*_*lye 6 android memory-leaks kotlin
我在活动中有一段简单的代码......
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
}
});
valueAnimator.start();
}
}
Run Code Online (Sandbox Code Playgroud)
如果活动终止,将会有内存泄漏(Leak Canary证明).
但是,当我将此代码转换为相同的Kotlin代码(使用shift-alt-command-k)时,如下所示
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f)
valueAnimator.repeatCount = ValueAnimator.INFINITE
valueAnimator.addUpdateListener { }
valueAnimator.start()
}
}
Run Code Online (Sandbox Code Playgroud)
内存泄漏不再发生.为什么?是因为匿名类对象被转换为Lambda?
这两个版本之间的区别非常简单.
Java版本AnimatorUpdateListener包含对外部类的隐式引用(在您的情况下为MainActivity).因此,如果动画在不再需要活动时继续运行,则侦听器会持续保持对活动的引用,从而防止对其进行垃圾回收.
科特林试图在这里变得更聪明.它看到你传递给它的lambda ValueAnimator不引用外部作用域中的任何对象(即MainActivity),因此它会创建一个单独的实例,AnimatorUpdateListener只要你[重新]启动动画,它就会被重用.并且此实例没有对外部作用域的任何隐式引用.
旁注:如果将对外部作用域中某个对象的引用添加到lambda,Kotlin将生成每次动画重新启动时创建更新侦听器的新实例的代码,这些实例将保持隐式引用MainActivity(为了访问您决定在lambda中使用的对象所必需的).
另一方面注意:我强烈建议阅读名为"Kotlin in Action"的书,因为它包含了很多有关Kotlin的有用信息,以及我对Kotlin编译器如何选择是否将隐式引用放入外部范围的解释SAM转换后创建的对象是否来自本书.
我想您会发现 \xe2\x80\x9cShow Kotlin Bytecode\xe2\x80\x9d 视图对于准确了解正在发生的情况非常有帮助。请参阅此处了解 InteliJ 快捷方式。\n (本来可以为您完成此操作,但如果没有更多应用程序的上下文,这很难)
\n\n但由于 Kotlin 与 Java 运行在相同的 JVM 上(因此使用与 Java 相同的垃圾收集器),因此您应该期待一个类似安全的运行时环境。话虽这么说,当涉及到 Lambda 和显式引用时,当它们被转换时。在不同的情况下它可能会有所不同:
\n\n与 Java 一样,Kotlin 中发生的情况在不同情况下会有所不同。
\n\n\n\n\n\n
\n- 如果将 lambda 传递给内联函数并且\xe2\x80\x99t 标记为 noinline,那么整个事情就会消失,并且不会
\n
创建任何其他类或对象。- 如果 lambda 没有\xe2\x80\x99t 捕获,那么它\xe2\x80\x99 将作为单例类发出,其实例被一次又一次地重用(一个类+一个\n 对象分配)。
\n- 如果 lambda 捕获,则每次使用 lambda 时都会创建一个新对象。
\n
来源: http: //openjdk.java.net/jeps/8158765
\n\n这个答案应该解释你所看到的,我自己无法更好地解释它: https: //stackoverflow.com/a/42272484/979052 \n不同的问题,我知道,但背后的理论是相同的 - 希望有所帮助
\n| 归档时间: |
|
| 查看次数: |
633 次 |
| 最近记录: |