如何解决 Dalvik 编译器对 64K 方法的限制问题?

Posted

技术标签:

【中文标题】如何解决 Dalvik 编译器对 64K 方法的限制问题?【英文标题】:How to solve the issue with Dalvik compiler limitation on 64K methods? 【发布时间】:2013-03-04 10:28:03 【问题描述】:

我和我的团队从另一个团队继承了一个大型 android 项目。据报道,包含所有库的整个应用程序有大约 35000 个方法。我们现在的任务是在需要使用 Protocol Buffers 的应用中实现新服务。

问题是生成的 .jar 文件包含所有必需的 .proto 文件创建另外几个 35000 个方法,即 70000 个方法。如果您不知道,Android 编译器对每个 .dex 文件有 65536 个方法的限制。我们显然超出了该限制,并且在尝试编译应用程序时遇到以下错误:

Unable to execute dex: method ID not in [0, 0xffff]: 65536
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536

是的,应用程序架构可能应该进行重组,但这需要时间。目前,我们正在尝试找出一个临时解决此问题的解决方案。

有什么建议吗?

【问题讨论】:

Facebook 团队前几天刚刚发布了一条关于这个确切问题的消息。 facebook.com/notes/facebook-engineering/… 如果您的应用程序包含这么多方法(并且您无法摆脱其中一些方法),则解决方案可能必须将应用程序拆分为可以构建到单独 dex 文件中的较小部分.有关如何执行此操作的示例,请参阅 this blogpost。 @Rawkode:Facebook 问题是由于旧版 Android(froyo、姜饼)中的“LinearAlloc”缓冲区过小所致。 64K 方法参考限制已融入 Dalvik 指令本身。 看到这篇文章 [***.com/questions/15209831/… [1]: ***.com/questions/15209831/… 【参考方案1】:

您可以使用另一个 DEX 文件。这就是你的做法:

http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html

【讨论】:

这是一个统计每个 jar 中方法数的脚本:gist.github.com/toms972/c83504df2da1176a248a 链接的帖子有点过时了,它展示了如何在基于 Ant 的项目中加载多个 DEX 文件。它还直接使用 DexClassLoader,这是不再需要的东西,因为 android.support.multidex 可以帮助您,并且它在支持库(修订版 21)中可用。关于如何将 MultiDex 集成到您的应用程序的详细说明在这里:contentful.com/blog/2014/10/30/… 类似于@TomSusel 脚本,我们编写了一个小的 gradle 插件,可以让您更深入地了解您的方法计数以及它在每个构建中的来源 - github.com/KeepSafe/dexcount-gradle-plugin【参考方案2】:

启用 Proguard (http://developer.android.com/tools/help/proguard.html) 以删除未使用的方法。 protobuf 生成器创建了数千个从未实际使用过的方法。

微型原型缓冲区 (https://code.google.com/p/micro-protobuf/) 也可能有用。

【讨论】:

我一直在研究为此使用 proguard,但我不确定如何在 Eclipse 中启用它以进行调试/运行配置构建。对此有何提示? *** 上有一些帖子可能会有帮助,比如***.com/questions/4732656/…。 我似乎找不到任何关于在 Eclipse 中使用 proguard 和调试/运行配置的问题...【参考方案3】:

Square 也有类似的问题,他们构建了Wire 来处理由 protobufs 引起的方法爆炸。他们声称已经杀死了 10,000 种方法。

【讨论】:

【参考方案4】:

在 6.5 之前的 Google Play 服务版本中,您必须将整个 API 包编译到您的应用中。在某些情况下,这样做会使您的应用中的方法数量(包括框架 API、库方法和您自己的代码)保持在 65,536 个限制以下变得更加困难。

从 6.5 版开始,您可以有选择地将 Google Play 服务 API 编译到您的应用中。例如,要仅包含 Google Fit 和 Android Wear API,请在 build.gradle 文件中替换以下行:

compile 'com.google.android.gms:play-services:6.5.87'

这些行:

compile 'com.google.android.gms:play-services-fitness:6.5.87'
compile 'com.google.android.gms:play-services-wearable:6.5.87'

更多参考,可以点击here

【讨论】:

【参考方案5】:

如果这是第一次使用协议缓冲区,您可以查看替代 JavaME 实现,即

protobuf-javame protobuf-j2me

Third party add ons 中还列出了其他人。如果没有使用它们中的任何一个,但它们似乎更小,并且没有标准协议缓冲区创建的所有方法。

【讨论】:

【参考方案6】:

我们最近在 Android 中添加了Nano Protobufs,这大大减少了生成的方法数量。

【讨论】:

如果您愿意,请提供更多详细信息? 是的,请...更多详细信息,了解我们究竟需要做什么才能开始使用 Nano Protobufs...【参考方案7】:

如果您使用的是 eclipse,这是解决 Click Here! 最简单的工作

【讨论】:

以上是关于如何解决 Dalvik 编译器对 64K 方法的限制问题?的主要内容,如果未能解决你的问题,请参考以下文章

安卓应用方法数超过64k解决办法:分割Dex

Android ART 运行时是不是具有与 Dalvik 相同的方法限制限制?

如何反编译 android 中 /data/dalvik-cache/arm 下的文件

smali文件语法

如何编译 Dalvik 以在 Linux 上本地运行它?

参考 Dalvik 或 Java 虚拟机?