Dalvik VM & Java 内存模型(Android 上的并发编程)

Posted

技术标签:

【中文标题】Dalvik VM & Java 内存模型(Android 上的并发编程)【英文标题】:Dalvik VM & Java Memory Model (Concurrent programming on Android) 【发布时间】:2011-10-21 20:48:30 【问题描述】:

我正在从事涉及大量并发编程的 android 项目,我将实现一些自定义线程间通信的东西(来自 java.util.concurent 的那个不太适合我的目的)。

一般来说并发编程并不容易,但使用 Dalvik 似乎更难。要获得正确的代码,您应该知道一些具体的事情以及 Dalvik 出现问题的地方。我只是找不到有关 Dalvik VM 的详细文档。大多数 Android 资源(甚至 developer.android.com 都专注于平台 API,并且没有提供有关某些重要(或低级)事物的任何深入信息)。

例如,Dalvik VM 符合哪个版本的 Java 语言规范?根据答案,volatile 变量的处理是不同的,并且会影响使用 volatile 变量的任何并发代码。

已经有一些相关的问题了:

Is Dalvik's memory model the same as Java's? Double checked locking in Android

fadden 的一些回答非常有用,但我仍然想更详细、更全面地了解相关问题。

下面是我感兴趣的原始问题(如有必要,我会更新列表,因为之前问题的答案将会到来):

    在哪里可以找到有关 Dalvik VM 的详细信息,可以为以下问题提供答案? Dalvik VM 符合Java 语言规范的哪个版本? 如果 (2) 的答案是“第三版”,那么 Dalvik 在本规范中对 Java 内存模型 的支持有多完善?尤其是对volatile变量语义的支持如何完善?

    在Double checked locking in Android fadden 中提供以下评论:

    是的。添加“volatile”关键字后,这将适用于单处理器(所有版本的 Android)和 SMP(3.0“honeycomb”及更高版本)

    是不是说Samsung Galaxy SII是双核CPU,但只有Android 2.3可能会错误的执行并发代码? (当然 Galaxy 只是一个例子,问题是关于任何具有 pre-Android 3.0 平台的多核设备)

    在Is Dalvik's memory model the same as Java's? 中,fadden 用以下句子提供答案:

    就 JSR-133 而言,目前没有一个 Dalvik 的发布版本是完全正确的

    这是否意味着任何现有的正确并发 Java 代码都可能在截至发布此评论之日发布的任何 Android 版本上无法正常运行?

更新#1:回复@gnat 的评论(太长也不能发表评论)

@gnat 发表评论:

@Alexey Dalvik 不符合任何 JLS 版本,因为符合要求需要通过 JCK,这不是 Dalvik 的选项。 这是否意味着您甚至不能应用标准 Java 编译器,因为它符合标准规范? 这有关系吗?如果是,怎么做?

嗯,我的问题有点模棱两可。我真正的意思是JLS 不仅是Java 编译器实现的规则,而且是任何JVM 实现的隐式 指南。实际上,例如,JLS 声明某些类型的读取和写入是 原子 操作。这对编译器编写器来说不是很有趣,因为读/写只翻译成单个操作码。但是对于任何JVM 实现来说,应该 正确实现这些操作码是必不可少的。现在你应该明白我在说什么了。虽然 Dalvik 接受并执行使用标准 Java 编译器编译的程序,但没有任何保证它们被正确地执行 (如您所料)只是因为没有人(也许 Dalvik 的开发人员除外)知道程序中使用的所有 JLS 功能是否都受到 Dalvik 的支持。

很明显 JCK 对于 Dalvik 来说不是一个选项,这没关系,但是程序员真的应该知道 JLS 的哪些 特性他们在 Dalvik 上执行代码时可能会依赖。但是文档中没有任何关于此的文字。虽然您可能期望像 =、+、-、* 等最简单的运算符可以像您期望的那样工作,但像 volatile 变量的语义这样不平凡的特性会怎么样(这在第 2 和第 2 中有所不同) JLS 第 3 版)?后者并不是您在 JLS 中尤其是在 Java 内存模型 中可能找到的最重要的东西。

【问题讨论】:

*** 对于这些东西都不是特别好的资源。您在询问平台实施问题; *** 倾向于专注于 Android SDK。对于您的各种问题,我推荐groups.google.com/group/android-platform。 请注意,fadden 是 dalvikvm 的作者,所以您可以相信他告诉您的内容。 @Alexey Dalvik 不符合任何 JLS 版本,因为符合要求需要通过 JCK,这不是 Dalvik 的选项。 这是否意味着您甚至不能应用标准 Java 编译器,因为它符合标准规范? 这有关系吗?如果是,怎么做? 从 Honeycomb (3.0) 开始,Dalvik 确实提供了所有重要的 JSR-133 保证。 Dalvik 不是 Java,因此一般不能保证 JLS,但对于 volatile 和原语的分词确实有正确的行为。最近在developer.android.com/training/articles/smp.html 上提供了 Android 上的 SMP 问题概述(重点关注 C++、Dalvik 和 ARM)。 Volatile 是根据 JMM 实现的。您正在运行的代码太简单,无法显示细微的差异。您可以尝试 Android SMP Primer 附录 (developer.android.com/training/articles/…) 中的示例;我观察到在 Android 上没有volatile 会失败。不过,我还没有在最近的设备上尝试过。 【参考方案1】:

我还没有完全阅读你的问题, 但首先不要使用 volatile,即使是 opengles 编码器也不会将其用于不同的 ui 和渲染器线程。

当且仅当一个线程写入时才使用 volatile(比如某个类的静态属性) 和其他读取,即使那样你也必须同步,阅读这个以获得一些处理计数的好方法

How to synchronize a static variable among threads running different instances of a class in java?

    始终使用同步 不要因为并发编程等困难主题而跳入大型项目 查看有关游戏的 android 示例,他们讨论了可运行对象的概念, 处理程序,并在 b/w 线程(UI 线程和渲染线程)中交换消息。

【讨论】:

【参考方案2】:

我想你回答了你自己的问题,虽然你没有详细说明为什么 java.util.concurrent 包不适合你的需求,但大多数移动应用程序只是使用异步 IO 和最少的线程。这些设备不是能够进行严重分布式处理的超级计算机,所以我有点难以理解为什么 java.util.concurrent 不能满足您的需求。

其次,如果您对 Dalvik 实现以及它是否符合 JLS(它不符合)有疑问,似乎可以推断,对线程机制的唯一可靠支持将是语言定义的那些 - java.util。并发、可运行和线程本地存储。

在内置语言支持之外手动滚动任何东西只会带来麻烦,并且正如您的问题所暗示的那样,Dalvik 可能不会以一致的方式得到支持。

与往常一样,当您认为自己可以比编写 Java 的人更好地编写线程时,请三思。

【讨论】:

【参考方案3】:

Dalvik 不符合任何 JLS 版本,因为符合要求需要通过 JCK,这不是 Dalvik 的选项。 复制自评论>

程序员真的应该知道在 Dalvik 上执行代码时他们可能依赖 JLS 的哪些功能

我认为他们知道的唯一方法是研究 Dalvik 测试套件(我打赌有一个,我希望它是开源的,不是吗?)。对于您需要的任何功能,1) 尝试查找如果 您的功能 实施不正确会失败的测试,并检查测试看起来是否足够好。如果没有这样的测试或不够好,1a) 添加新的或改进现有的测试。然后,2) 确定测试是否已针对您的目标实现成功运行。如果测试没有运行,那么 2a) 自己运行它,看看它是通过还是失败。

BTW 上面大致介绍了 JCK 的工作原理。主要区别在于,人们必须在 Dalvik 上投入自己的时间和精力,才能从 Sun/Oracle 获得理所当然的东西。另一个区别似乎是,对于 Dalvik 这没有记录,而 Snorcle 在该 iirc 上有明确的文档

但文档中没有任何关于此的文字。

好吧,如果没有的话,那么我会说 Dalvik 文档的质量是次优的。轻声细语

【讨论】:

Dalvik 文档不是最理想的。根本没有公开的 Dalvik 文档,API 文档也不好:例如您可能会找到带有返回值的构造函数的描述(很好;)),但很少看到有关方法的前置条件和后置条件的有用注释。至于您提出的测试......好吧,有人可能会尝试但请注意以下几点:如果您想使用任何现有的Java代码库怎么办?似乎不同版本的Android都有不同版本的Dalvik,如果他们没有合理的共同支持特性集你会怎么做? @Alexey 好吧,Android 平台的流行让我觉得你提出的问题并不是那么重要。顺便说一句,对于您提到的所有 what-if,我至少可以想到一种方法来解决这些问题 - 没有一种方法是火箭科学,可以通过一点思考和应用来弄清楚常识。引用自己的话,必须在 Dalvik 上投入自己的时间和精力 你提出的担忧并不那么重要。对于 Android 智能手机和平板电脑的用户来说可能。但我个人对我的 Galaxy S 和 A500 不太满意,因为浏览器(A500,挂断)、Android 市场(A500,应用程序安装成功率是 50/50)、后台运行的动态壁纸( Galaxy S,只是浪费电池)等等。质量问题。我真正想知道的是在最初的帖子中提出的。在我得到答案之前,我不能说我的代码是质量的(假设与一致性),作为开发人员,我对此并不满意。 作为开发者我明白了。鉴于 Android 的开源性质,我认为您最好准备好自己担任测试人员(包括但不限于担任一致性测试人员)。如果您之前作为开发人员的背景是 Java(JCP、JLS、JCK、JDK、文档和规范) - 忘记它:所有这些之前由 Snorcle 完成的无聊、繁琐(有时令人兴奋)的测试工作场景现在都是你的了 自 3.0 以来,Android 不再是开源的 AFAIK。【参考方案4】:

这是诚实的答案。如果 java.util.concurrent 不能满足您的实现任务,那么您的问题不是 java.util.concurrent 而是您的原始设计规范。重新审视您的设计,也许在此处发布您的设计中使用简单互斥锁无法满足您的任务的内容,然后社区可以向您展示如何更好地设计它。

【讨论】:

以上是关于Dalvik VM & Java 内存模型(Android 上的并发编程)的主要内容,如果未能解决你的问题,请参考以下文章

Android内存优化1 了解Android是如何管理App内存

Android 源码分析 Dalvik 虚拟机创建过程

在服务器上使用 Dalvik VM 进行 Web 开发?

Android Dalvik虚拟机 堆内存管理 增长&释放

Android Dalvik虚拟机 堆内存管理 增长&释放

androd应用内存使用情况