这是 Android Performance Patterns 第五季的第三集,之前视频中一直在介绍线程的重要性,以及 Android 中我们提供的一些类功能和使用场景,这一集老外会讲一讲内存和线程的关系。

本期视频地址 https://www.youtube.com/watch?v=tBHPmQQNiS8

(老外四分钟讲了这么多,我的心在滴血...)

As much as we'd like focus on creating and managing thread and work packets, we tend to ignore the biggest, hardest problem in threading, memory.

我们想要尽可能专注于创建和管理线程以及代码中的任务,而趋向于忽视线程和内中最大,最难的问题。

My name is Colt McAnils.

大家好,我叫Colt McAnils.

And while threading and memory have a long, complicated history in programming, there are some specific nuances on Android that you need to be aware of.

虽然线程和内存在编程中有着在复杂而漫长的历史,但 Android 中还有一些需要注意的细微的差别。

You gotta remember that memory in computing isn't really thread safe.

你需要记住的是,在内存中计算并不是线程安全的(这么理解对么)。

When two threads are operating on the same block of memory, weird things happen.

当两个线程操作同一个代码块时奇怪的事情就会发生了。

两个线程同时操作一个区域会发生奇怪的事情.png

I mean, you can get memory contention problem with read write access order, ABA problem, rips in the fabric of space time.

我是说,读写访问顺序可能带来,内存争用、ABA、空间时间的结构中破裂等问题,不知道这么理解正不正确。

ABA 问题可以参考维基百科,地址如下:

https://zh.wikipedia.org/wiki/%E6%AF%94%E8%BE%83%E5%B9%B6%E4%BA%A4%E6%8D%A2

Ok, maybe not --- maybe not the last one.

好吧,也许不是最后一个(这句话太突兀了吧)。

But anyhow, fixing these means restricting memory access form threads using locking, which is a whole separate video series that we're not going to get into right now.

但无论如何,修复上面那些问题就意味着通过锁的形式限制内存访问线程(就是加锁呗),后半句我对它的理解是,这是一套完整视频系列,但是我们现在不会深入讲解,不知道这么理解对不对。

But most important to understand is that Android isn't immune to these problems.

但是最重要的是理解其实 Android 中也不能避免这些问题。

For the most part, the same techniques you use to deal with these issues on other platforms can be applied here, too.

在大多数情况下,我们可以在这里使用同样手法去处理同其他平台上遇到问题,所以就是手法是相似的,在别的地方遇到问题,在这里也遇到了,那么我们就可以使用同样的手法去处理这些问题。

But there a few specific cases that you need to be aware of.

但我们我也需要注意一些特殊的情况。

Let's start with the fact that by desgin, UI objects are not thread safe.

来让我们看一个设计的事实,UI 对象不是线程安全的(这么理解对么)。

UI objects are expected to be created, used, and destroyed all on the UI thread, and not guaranteed to behave properly on any other threads.

UI 对象被预期在 UI 线程(主线程)被创建、使用和销毁,但不能保证在其他线程也都能正常运行。

Trying to modify or even reference them on other threads can throw exceptions, cause silent failures, crashed, and just general weirdness.

尝试在其他线程修改或者甚至引用 UI 对象 可能会导致异常、引发一些无声的失败、崩溃或者一些普通的奇怪现象。

尝试在其他线程修改 UI 会有失败,崩溃之类的问题.png

In fact, just holding a direct reference to a UI Objcet on the work thread can be a problem.

事实上,只是在工作线程直接持有一个 UI 对象的引用也可能会导致问题。

For example, your work object may contain a reference to a view.

例如,在工作对象可能包含对一个视图的引用。

But before your work completes on the worker thread, the view is removed from the view hierarchy on the main thread.

但是,在工作线程完成之前,该视图已经从主线程的视图层次结构中被删除了。

So 别在工作线程操作 UI.png

So what do you do here?

这时候会发生啥呢?

I mean, you can't trust any of the properties of that view since the data has changed.

这句话应该怎么理解呢?由于数据已经修改了,所以不能相信视图的任何属性,应该是承接上面那句,该视图已经从主线程的视图层次结构中被删除了,所以就不要相信视图的任何属性,也不要试图再去操作 View。

And updating those properties dosen't really mean anything, since it's not part of the hierarchy anymore and won't be drawn to the screen.

并且更新这些属性不会真的意味着什么,因为它不再是层次结构的一部分,也不会被绘制到屏幕上,所以果然是已经被从视图层级中删除了,所以再去更新他们的属性并没有什么卵用。

Now remember, views contain reference to their owning activity.

现在记住,视图控件包含着他们自己所在的 Activity 的引用。

I mean, we did a whole video on how leaking those views can cause all sorts of memory problems.

我是说,之前的视频中(第三季),说过这些视图控件可能引起内存泄漏等问题。

第三季第六集讲的内存泄漏.png

But this gets even worse when threading is involved.、

但如果涉及到线程,可能问题会更糟。

If an activity is destoryed but there still exists a threaded block of work that reference it, the activity won't get collected util that work finishes.

如果 Activity 被销毁了但是工作线程还引用着它,那么 Activity 将不会被回收直到线程工作完毕。

其他线程还持有着 Activity 的引用,导致 Activity 无法被回收,直到线程工作结束.png

So if you kick off some work and the user rotates the screen three times in a row before that work completes, you could end up with three instances of that activity object resident in memory.

如果你开始一些工作(代码中的一些任务),并且用户在任务完成之前旋转了三次屏幕,那么就可能会在内存中存在三个该 Activity 的实例,毕竟旋转屏幕正常情况下会销毁并重建该 Activity。

And to be clear, it's not just explicit references to UI objcets that you need to worry about.

需要明确的是,你担心的不仅仅是明确引用的 UI 对象,应该还有很多,如果使用不当,都会造成内存问题,比如内存泄漏。

You also have to be cautious of implicit references, as well.

你也不得不小心点隐式引用,比如内部类会隐式持有外部类的引用。

Check out this very common seen-all-the-time coding pattern in Android apps.

在 Android App 中查看这个非常常见的编码模式,这句话翻译的不是很好。

You're got some threading object that's declared as an inner class of an activity.

你在 Activity 中声明了一些作为内部类的线程对象。

The problem here is that the async task object now has an implicit reference to the enclosing activity and will keep that reference until the work object has been destory.

这里的问题就是,异步的任务对象也就还下图中的 MyAsyncTask 是一个内部类,那么它就会隐式的持有 Activity 对象的引用,并保留着该引用知道一异步工作的对象被销毁,这里是内部类的只是点,如果我们将 MyAsyncTask 声明为嵌套类(静态内部类)那么就不会有再持有外围类对象的引用了。

Activity 中的内部类会隐式持有 Activity 的引用.png

The result is the same problem.

这句话意思应是说,返回的结果也同样是一个问题。

Until this work completes. the activity stays around in memory.

直到异步任务完成,Activity 还依然会留在内存中。

And by the way, this type of pattern also leads to common types of crashed seen in Android apps.

顺便提一句,这种类型的的模式也是导致 Android 应用中常见的崩溃的原因之一。

而且还可能会导致 App 崩溃.png

Some block of threading work has kicked off.

一些线程工作已经开始了。

But the uesr hint Back or does something else to change the top-most activity.

但是用户点了返回或者其他什么事情改变了最顶端的 Activity。

Later, when the threaded work completes, it tries to make updates to a state that's no logger valid.

之后,当线程任务完成后,它尝试着更新一个不再有效的状态。

The result is a dialog box notifying me that an app I haven't used for 10 minutes has crashed, which is kind of awkward for everybody.

如果任务结束了,结果需要是一个对话框通知用户,那么那个已经10分钟没使用的应用就会崩溃,这对每个人来说都略显尴尬。

The takeaway here is that you shouldn't hold references to any types of UI specific objects in any of your threading scenarios, which leads to the natural question, how are we suppsed to update the UI from threaded work.

所以你不应该在任何线程场景中保留着任何类型的 UI 对象的引用,这将导致一个自然问题,我们应该如何从线程工作中去更新 UI。

不要持有引用.png

The trick here is to force the top level activity or fragments to be the sole system responsible for updating the UI objects.

这里的诀窍是强制位于顶层的 Activity or Fragment 成为更新 UI 对象的唯一负责人。

For example, when you'd like to kick off some work, create a work record that pairs a view with some update function.

举个例子,当你想要开始一些任务时,创建一个将视图与一些功能匹配的工作记录,卧槽,这句话这么翻译好像不太好吧。

When that block of work is finished, it submits the results back to activity using an intent or a run on UI thread call.

当任务代码块执行结束后,它会使用 Intent 或者在主线程中将结果返回给 Activity。

The activity can then call the update function with the new information, or if the view isn't there, just drop the work altogether.

Activity 可以使用新的信息来回调更新函数,或者如果 View 对象已经不存在了,那么及应该将任务一起删掉。

然后,活动可以使用新信息调用更新功能,或者如果视图不在那里,则只需将工作完全删除。

And if the activity that issued the work was destoryed, then the new activity won't have a reference to any of this and will just drop the work too.

应该是说如果 Activity 被销毁了,那么基于这个 Activity 运行的任务也应该都停止掉,别影响别的 Activity 工作。

See?

看到了没?

No crashed, no memory leaks, just pure clean fun.

没有崩溃,没有内存泄漏,只是安静的写着代码,而不是写着Bug,这才是纯粹的编码乐趣。

Now, if you ever want a deeper look at how threading and memory are working together, make sure to check out the powerful new tools inside of Android Studio, which just got an awesome revamp as a version 2.0.

AS 2.0 提供一个工具,它可以帮助我们更深入地了解线程和内存如何协同工作,但这个工具我暂时还没找到哪里打开。。。

AS 2.0 提供的一个查看线程工具.png

The deeper you go into Android performance, the more you realize how important memory is on this platform, which is why should check out the rest of the memory videos on the Android Performance Patterns playlists.

打广告,记得来看他们的 Android Performance Patterns 视频。

....以下略,即可以去 Google+ 和他们进行交流...

可能有些地方翻译的不正确,我会尽力提升自己翻译的准确度,并用自己的语言表达出来,捎带手会提一些视频的知识点,欢迎讨论。

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. Android--Handler使用应运及消息机制处理原理分析
  3. EventBus源码解析-总结篇
  4. Android(安卓)超强图片工具类BitmapUtil
  5. adnroid:layout_weight
  6. [转发]Android(安卓)系统稳定性 - ANR(三)
  7. ConditionVariable的简介和用法
  8. 天天记录 - Android(安卓)AsyncTask 缺陷
  9. Android(安卓)引用使用外部字体

随机推荐

  1. Android(安卓)工程混淆后无法找到自定义
  2. Android(安卓)Handler(四)
  3. Android之传感器(一)
  4. 一种巧妙获取Android状态栏高度的办法
  5. Cocos2dx杂记:仿Android提示Toast
  6. 14天学会安卓开发(第十天)Android网络与
  7. 在eclipse创建android 工程
  8. Android开发学习
  9. 今天的小收获
  10. Android核心分析(链接)