首先,本文的代码位置在**https://github.com/marcosholgado/performance-test/tree/kotlin-mem-leak**中的kotlin-mem-leak分支上。 我是通过创建一个会导致内存泄漏的Activity,然后观察其使用Java和Kotlin编写时的表现来进行测试的。 其中Java代码如下:
public class LeakActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leak);
View button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startAsyncWork();
}
});
}
@SuppressLint("StaticFieldLeak")
void startAsyncWork() {
Runnable work = new Runnable() {
@Override public void run() {
SystemClock.sleep(20000);
}
};
new Thread(work).start();
}
}
如上述代码所示,我们的button点击之后,执行了一个耗时任务。这样如果我们在20s之内关闭LeakActivity的话就会产生内存泄漏,因为这个新开的线程持有对LeakActivity的引用。如果我们是在20s之后再关闭这个Activity的话,就不会导致内存泄漏。 然后我们把这段代码改成Kotlin版本:
class KLeakActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_leak)
button.setOnClickListener { startAsyncWork() }
}
private fun startAsyncWork() {
val work = Runnable { SystemClock.sleep(20000) }
Thread(work).start()
}
}
咋一看,好像就只是在Runable中使用lambda表达式替换了原来的样板代码。然后我使用leakcanary和我自己的@LeakTest注释写了一个内存泄漏测试用例。
class LeakTest {
@get:Rule
var mainActivityActivityTestRule = ActivityTestRule(KLeakActivity::class.java)
@Test
@LeakTest
fun testLeaks() {
onView(withId(R.id.button)).perform(click())
}
}
我们使用这个用例分别对
Kotlin Lambda与内存泄漏的秘密

本文通过对比Java和Kotlin代码,分析了内存泄漏的原因,指出Kotlin中使用Lambda表达式可以避免某些情况下的内存泄漏。作者创建了一个示例,展示了在Android中由于线程持有Activity引用导致的内存泄漏问题,并通过字节码分析,揭示了Kotlin如何通过静态方法处理Lambda,从而避免内存泄漏。实验结果显示,Kotlin的Lambda在特定情况下表现得更优。
最低0.47元/天 解锁文章
946

被折叠的 条评论
为什么被折叠?



