[译] 内存泄露的八种花样,app 优化的内容及策略
view = findViewById(R.id.sv_button);}
View svButton = findViewById(R.id.sv_button);svButton.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {setStaticView();nextActivity();}});
静态 View 内存泄露
等下!看到没。你知道一个 attach 了的 view 内部会持有一个指向 Context 的引用,换句话说,那就是我们的 Activity。通过吧一个 View 设为静态变量,我们创建了一个能长期持有 Activity 的引用链,导致 Activity 被泄露了。千万不要把 attach 的 view 设为静态变量,如果实在必须这么做,至少保证在 Activity 的生命周期结束前把它从 View 的层级结构里[detach](
))掉。
3. 内部类
除了这,让我们在我们的 Activity 类里在定义一个类,也就是[内部类](
)。为了提高代码的可读性和健壮性,封装程序逻辑,我们可能会这么做。如果我们创建了一个这样的内部类的实例,并通过静态变量持有了它,会怎样呢?你应该能猜到这又是一个内存泄露的点。
void createInnerClass() {class InnerClass {}inner = new InnerClass();}
View icButton = findView
ById(R.id.ic_button);icButton.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {createInnerClass();nextActivity();}});
内部类导致的内存泄露
不幸的是,由于内部类可以直接访问到它的外部类的变量,这个特性意味着内部类会隐式的持有一个对它的外部类的引用,这间接导致了我们不小心又泄露了 Activity。
4. 匿名类
同样的,匿名类也持有一个指向它申明的地方所在的类的引用。如果你在[Activity 内定义和实例化一个 AsyncTask 匿名类](
),那也可能发生内存泄露
void startAsyncTask() {new AsyncTask<Void, Void, Void>() {@Override protected Void doInBackground(Void... params) {while(true);}}.execute();}
super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);View aicButton = findViewById(R.id.at_button);aicButton.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {startAsyncTask();nextActivity();}});
AsyncTask 的内存泄露
5. Handler
同样的原则也适用于后台任务:[定义一个匿名的 Runnable,然后将它加入 Handler 的处理队列里](
)。这个 Runnable 对象会隐含的持有一个指向它定义的时候所在的 Activity 的引用,然后它会作为一个消息对象加入到 Handler 的消息队列里去。在 Activity 生命周期结束之后,只要这个消息还没被 Activity 处理,那就有一条引用链指向我们的 Activity 对象,使得 Activity 对象无法被回收,进而泄露。
void createHandler() {new Handler() {@Override public void handleMessage(Message message) {super.handleMessage(message);}}.postDelayed(new Runnable() {@Override public void run() {while(true);}}, Long.MAX_VALUE >> 1);}
View hButton = findViewById(R.id.h_button);hButton.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {createHandler();nextActivity();}});
Handler 导致的内存泄露
6. 线程
类似的问题我们可以在[线程](
)、[定时任务(TimerTask)](
)里发现。
void spawnThread() {new Thread() {@Override public void run() {while(true);}}.start();}
View tButton = findViewById(R.id.t_button);tButton.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {spawnThread();nextActivity();}});
线程使用不当导致内存泄露
评论