首先,本文的代码位置在**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())
}
}
我们使用这个用例分别对