Android Dex 64k Method Size Limit

Android线性内存分配器LinearAlloc分析 因为毕业设计做Dalvik内存管理方面的优化。 这些天仔细阅读了下线性分配器LinearAlloc的代码 线性分配器代码为于android_src/dalvik/vm/目录下的 只有两个文件LinearAlloc.h和LinearAlloc.c代码很少,约800多行而已 线性分配器的目的在于简单、快速地分配只写一次(write-once)的内存(即分配并完成初始化写入后一般不会再改变,保持 阅读详情

###问题
Android 开发一年以上或者更久,大部分会遇到如下问题:

  • 64K

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

  • LinearAlloc

ERROR/dalvikvm(4620): LinearAlloc exceeded capacity (5242880), last=…

如果你遇到这个问题,那么恭喜你,因为你的app可以存活这么久(o)/~, 开完玩笑,我们进入正题,了解一下上面问题产生的原因。

###原因

  • 64K

.dex 文档是 Dalvik EXecutable,里面存的是 dex byte code,可在 Davlik VM 上执行。你 unzip 解开 .apk 后悔看到一个 classes.dex 文档,就是它了。不过,dex method 64k 上限跟 dex 文档的格式无关。根据stackoverlfow 回应的说法,是因为 Dalvik 指令集里,执行 method 的 invoke-kind index 大小只给了 16bit,所以一個 Android APP只能执行前 65536 个 method,后面多的都不能用。
因为是指令集的限制,所以新一代 ART Runtime 也受同樣的限制。.dex 文档记录了method 总数,可以用 Android SDK 內附的 dexdump 指令查看你的 app 定义了多少个 method:(Linux Shell 脚本)

```shell
cd android-sdk-macosx
./build-tools/19.1.0/dexdump -f  /path/to/your/apk | grep method_ids_size
```
输出结果:

```shell
method_ids_size     : 51306
```
5万个 method 很多啊,快到64k上限了,一个app会有如此多的method?后面来分析这一大票 method 是什么鬼。

如果你使用Android Studio 那么可以考虑Github上的一个小插件 [dex-method-counts][1], 或者如果你不希望这个插件额外占用你的 app method, 那么直接使用 JS 脚本检测你的APK method也是个好主意,这两者在统计method思路上是一致的,这里给出 部分 JS 代码
```JavaScript
//Written by Juraj Novák (inloop.eu)
...

DexFile.prototype.getMethodRefs = function () {
    var refs = [];
    for (var i = 0; i < methods.length; i++) {
        var method = methods[i];
        refs[i] = {};
        refs[i].className = classNameFromTypeIndex(method.classIdx);
        refs[i].argArray = argArrayFromProtoIndex(method.protoIdx);
        refs[i].returnType = returnTypeFromProtoIndex(method.protoIdx);
        refs[i].name = strings[method.nameIdx];
    }
    return refs;
};

DexFile.prototype.getHeader = function () {
    return dexFile;
};

function loadStrings(dv) {
    var curStrings = [];
    var offsets = [];
    dv.seek(dexFile.stringIdsOff);

    for (var i = 0; i < dexFile.stringIdsSize; i++) {
        offsets[i] = dv.getInt32();
    }

    dv.seek(offsets[0]);
    for (var i = 0; i < dexFile.stringIdsSize; i++) {
        dv.seek(offsets[i]);
        curStrings[i] = dv.readStringUtf();
    }
    strings = strings.concat(curStrings);
}

function loadTypes(dv) {
    var curTypes = [];
    dv.seek(dexFile.typeIdsOff);
    for (var i = 0; i < dexFile.typeIdsSize; i++) {
        curTypes[i] = dv.getInt32();
    }
    types = types.concat(curTypes);
}

function loadProtos(dv) {
    var curProtos = [];
    dv.seek(dexFile.protoIdsOff);
    for (var i = 0; i < dexFile.protoIdsSize; i++) {
        curProtos[i] = {};
        curProtos[i].shortyIdx = dv.getInt32();
        curProtos[i].returnTypeIdx = dv.getInt32();
        curProtos[i].parametersOff = dv.getInt32();
    }

    for (var i = 0; i < dexFile.protoIdsSize; i++) {
        var offset = curProtos[i].parametersOff;
        curProtos[i].types = [];
        if (offset != 0) {

            dv.seek(offset);
            var size = dv.getInt32();       // #of entries in list

            for (var j = 0; j < size; j++) {
                curProtos[i].types[j] = dv.getInt16() & 0xffff;
            }
        }
    }
    protos = protos.concat(curProtos)
}

function loadFields(dv) {
    var curFields = [];
    dv.seek(dexFile.fieldIdsOff);
    for (var i = 0; i < dexFile.fieldIdsSize; i++) {
        curFields[i] = {};
        curFields[i].classIdx = dv.getInt16() & 0xffff;
        curFields[i].typeIdx = dv.getInt16() & 0xffff;
        curFields[i].nameIdx = dv.getInt32();
    }
    fields = fields.concat(curFields);
}

function loadMethods(dv) {
    var curMethods = [];
    dv.seek(dexFile.methodIdsOff);
    for (var i = 0; i < dexFile.methodIdsSize; i++) {
        curMethods[i] = {};
        curMethods[i].classIdx = dv.getInt16() & 0xffff;
        curMethods[i].protoIdx = dv.getInt16() & 0xffff;
        curMethods[i].nameIdx = dv.getInt32();
    }
    methods = methods.concat(curMethods);
}

function loadClasses(dv) {
    var curClasses = [];
    dv.seek(dexFile.classDefsOff);
    for (var i = 0; i < dexFile.classDefsSize; i++) {
        curClasses[i] = {};
        curClasses[i].classIdx = dv.getInt32();
        curClasses[i].accessFlags = dv.getInt32();
        curClasses[i].superclassIdx = dv.getInt32();
        curClasses[i].interfacesOff = dv.getInt32();
        curClasses[i].sourceFileIdx = dv.getInt32();
        curClasses[i].annotationsOff = dv.getInt32();
        curClasses[i].classDataOff = dv.getInt32();
        curClasses[i].staticValuesOff = dv.getInt32();
    }
    classes = classes.concat(curClasses);
}
...

};
```
还有一部分JS,这里省略。了解上面的基本思路即可,具体如何统计 不是重点, 重点是我们来看看经过上面JS统计出来的结果如下:
![此处输入图片的描述][2]

然后重点来了,com包下有42912个method,是不是很吓人,展开以后我们一探究竟
![此处输入图片的描述][3]
有木有发现,我们自己的代码占了2万多,其他比较过分的分别是 Tencent,alibaba,umeng的sdk,另外还有fasterxml,这个大名鼎鼎,不过人家一开始就不是专门给Android开发的,所以一些流弊的包我们拿过来用的时候,一定要经过自己的判断,适合自己的才是好的。比如这个fasterxml就可以用google的json包代替,下面给出了常用的android 第三方包method统计。

![此处输入图片的描述][4]
  • LinearAlloc

有关 LinearAlloc 的问题,网路上已经有很好的解说。简单说就是 Android 程式执行前会将 class 读进 LinearAlloc 这块 buffer 裡,它的大小在 Android 2.3 之前是 5MB,到了 4.0 后才改成 8MB 或 16MB。5MB 太小了,通常你还没踩到 64k method 限制时,就会先踩到 LinearAlloc 的问题。
这个问题到了 4.0 才改善,但是 2.3 还有约10 % 的市场,所以我们还是得面对它。注意 5MB buffer 的限制不是 classes.dex 的档案大小的限制,像我们自家的 App classes.dex 的大小已经 7 MB 了,还是可以在 2.3 执行。最主要还是看 class 结构的複杂性,以及总 method 数。

看完上面两个问题产生的原因了,我们来综合看一下经常遇到的问题

  • INSTALL_FAILED_DEXOPT

安装 apk 时,如果出现上面提到的两种错误,你通常会看到错误讯息有 INSTALL_FAILED_DEXOPT 这行。dexopt 是 dex optimization 的意思,这一步骤会发生在安装完 apk 之后,它会检验 .dex 裡面的指令集是不是合法,也会验 method 的上限数。超过上限的话,app 还没启动就被这一步挡下,直接喷错。dexopt 也会试著将所有 class/method 都读进 VM 验证,这自然会运用到 LinearAlloc buffer。如果 buffer 不够也是直接喷了。所以程式太大的话,通通会死在 dexopt 这过程里。
上面的错误都已经很清晰的知道原因了,那么我们该如何判断app能安全在android2.3运行呢,接下来我们给出一般的经验值仅供参考。

  • 参考值56000 method(当然也可以判断 classes.dex文件不超过8M大小)

开发进行期间,维持 method 数在 65536 以下 (未 proguard)
开发时通常我们会用 Android 4.0 以上的手机来测,所以不用管56000 method 数的限制。但要确保尚未做 proguard 之前,总 method 数要小于 65536。相信我,如果开发时每次 build 都要做 proguard 才能将 method 数压在 65536 下,你会想死,每 build 一次都要几分钟以上啊。

###解决方案

有了上面的分析,下面解决方案就比较直接了,方法无外乎下面几条。

  1. 精简method
  2. 拆分包

对于以上两个方案说一下体会。

  1. 精简method 可以通过选择合适的第三方包,或者启用proguard,或者删除不用的方法等等,这种方式代价很小,但是毕竟有突破64k的时候,所以,也仅仅是临时的方案。
  2. 拆分包。android官方给出了一个不完整的解决方案,multiDex在gradle中配置即可,比较简单,但是解决不完整,详细可以参考其实你不知道MultiDex到底有多坑。
    另外有几篇介绍如何弥补android官方这个漏洞的解决方案,比较复杂,适合喜欢钻研的同学,这里列一篇文章Android拆分与加载Dex的多种方案对比。
【信息科学与工程学】计算机科学与自动化——第八十四篇 C++分布式软件高并发/高可用算法01 4. 提交:协调者选择提交时间戳(>所有读时间戳),两阶段提交:a) 写意图预提交到所有参与者,b) 参与者持久化后确认,c) 协调者决定提交,异步清理意图。:客户端请求发送到协调节点,协调节点根据路由转发到主分片所在节点。Span有父子关系。1. 索引文档:客户端发送PUT请求到协调节点,协调节点路由到主分片节点,主分片写入本地,然后并行复制到副本分片,等待确认后响应客户端。3. 搜索:客户端发送搜索请求到协调节点,协调节点广播到所有相关分片,每个分片执行查询,返回结果,协调节点合并、排序、分页后返回。 阅读详情

相关推荐

文本→图像→视频:AIGC跨模态转换全流程解析

本文旨在系统性地解析AIGC领域中跨模态内容生成的技术原理和实现方法,特别聚焦于从文本到图像再到视频的完整转换流程。跨模态表示学习的基本原理文本到图像生成的核心技术图像到视频转换的关键算法端到端跨模态生成系统的构建方法实际应用场景和性能优化策略背景介绍:建立基本概念和知识框架核心概念:解析跨模态转换的关键技术和原理算法细节:深入讲解文本到图像、图像到视频的核心算法数学模型:提供必要的数学基础和公式推导项目实战:通过完整案例展示实现过程应用场景:探讨技术的实际应用可能性。

AI天才研究院 1352

class文件与dex文件解析

这篇笔记是我去年的时候创建的,结果放到草稿箱里给忘记了,大写的尴尬啊,所以急忙给补上了,此处鄙视一下自己!今天的正题——解析class文件和dex文件。

江湖人陆仁甲 8888

实战拆解:RAG vs Agent在金融风控中的性能对比

2024年上半年我帮某华东地区城商行做零售交易反欺诈系统升级时,技术团队曾发生过一次激烈争论:一派认为应该优先上RAG(检索增强生成)方案,成本低、落地快、合规性好;另一派坚持要上Agent(智能体)方案,推理能力强、能应对复杂新型欺诈。最终我们做了完整的AB测试,结论是两者没有绝对的优劣,只有场景适配的差异:RAG适合高并发、低时延的实时风控场景,Agent适合低并发、高准确率要求的事后核查/大额审批场景,两者结合的 hybrid 方案能覆盖95%以上的风控需求。本文我会结合真实项目的测试数据,从核心概念

AI天才研究院 251

class和dex

class文件 概念:可以被JVM识别加载并执行的文件格式。java,scala,kotlin,python,ruby都可以生成class文件 怎么生成class文件: (1)通过我们的IDE ,build生成 (2)通过javac命令生成 怎么执行class文件 (1)通过IDE中的run执行 (2)通过java命令执行 class文件的作用:记录一个类文件的所有信息 class文件的结构: ...

mingyunxiaohai的专栏 3011

02-基于ART-PI开发板创建USB CDC 虚拟串口设备

本例在ART-PI开发板上,基于RT-Thread 5.0,5虚拟了一个USB32 CDC串口设备。

arm_fan的专栏 1885

基于VisionMaster的药丸外观缺陷机器视觉检测系统实战解析

机器视觉作为工业自动化的核心技术,通过图像采集与智能分析替代人眼,实现高精度、高效率的在线检测。其核心原理在于利用相机、镜头、光源等硬件获取目标图像,再通过图像处理算法提取特征并进行识别与判断。这项技术的核心价值在于能够大幅提升生产质量与效率,尤其在需要高速、高精度且重复性强的检测场景中优势显著。在制药、食品、电子等行业的表面缺陷检测、尺寸测量、字符识别等环节应用广泛。本文聚焦于制药行业的药丸外观缺陷检测这一具体应用,深入探讨了如何利用海康威视VisionMaster视觉平台,结合**Blob分析**与**

weixin_32903229的博客 312

Unable to execute dex: method ID not in [0, 0xffff]: 65536问题及解决办法

目录(?)[+] 預防 Android Dex 64k Method Size Limit 08 September 2014 如果你有 Android App 持續開發一年以上,那你多半已經遇過很有名的 Dex 64k method 數量上限: Unable to execute dex: method ID not in [0, 0xffff]: 6

Sun的专栏 2162

基于传输门与传输管逻辑的全加器设计

全加器是指对输入的两个二进制数相加(A与B)同时会输入一个低位传来的进位(Ci-1),得到和数(SUM)和进位(Ci)。一位全加器可以处理低位进位,并输出本位加法进位。由于这种晶体管的漏极和源极完全可以互换使用,因此这种电路的输入端与输出端也可以互换,这就是具有信号传输双向特性的传输管。传输管的输入信号可以传输到输出端,同时输出端的信号也可以传输到输入端。半加器是指对输入的两个一位二进制数相加(A与B),输出一个结果位(SUM)和进位(C),没有进位的输入加法器电路,是一个实现一位二进制数的加法电路。

qq_40353731的博客 4381

Android Multidex 遇到的问题

Android 的classLoader在加载APK的时候限制了class.dex包含的Java方法总数不能超过65535,但是现在随便一个复杂一点的App,轻而易举就能超过65535。为了解决这个问题,google推出了官方的解决方案——Multidex 一、使用之后,相信很多人都遇到过以下几个问题: 1. Dalvik LinearAlloc Limit 安装时异常  Installa

我的专栏 1万+

28、数字电路测试与半导体内存测试全解析

本文全面解析了数字电路中的顺序电路测试生成方法与半导体内存测试技术。内容涵盖顺序电路中的故障检测、多重观察测试、可驱动性分析、伪组合电路测试及初始化问题,并深入探讨了内存技术发展、故障模型、测试流程与未来趋势。重点介绍了DRAM、SRAM等主流内存类型的特点,以及制造和使用过程中面临的永久性与非永久性故障挑战,提出了基于故障模型的高效测试策略与优化方案。

go5gopher的博客 122

国家自然基金研究方向选定后,关键词只能下拉吗?——不是的,国家自然科学基金(NSFC)的关键词并不是只能下拉选择,而是:[特殊字符] “可选 + 可填”的混合模式(但以规范词为主)

你可以手动输入关键词用于表达新兴方向或细分领域✔ 适用情况:新概念(如“电场调控纳米流体”)交叉领域(如“电流体力学传热耦合”)电场调控电流体力学可以自己填,但必须以系统标准关键词为主,自定义为辅如果你愿意,我可以帮你做一件更关键的事:👉根据你题目,反向设计“最容易中标”的关键词组合 + 学科代码搭配这个比写内容本身还更影响送审质量。你可以手动输入关键词用于表达新兴方向或细分领域✔ 适用情况:新概念(如“电场调控纳米流体”)交叉领域(如“电流体力学传热耦合”)电场调控电流体力学。

qq_15963745的博客 81

android apk包在android 2.3以下系统上安装时遇到的INSTALL_FAILED_DEXOPT和LinearAlloc exceeded capacity问题解决方法

现象:安装APK时报INSTALL_FAILED_DEXOPT的错误,如果在eclipse中看log会有LinearAlloc exceeded capacity的异常 原因: 1.INSTALL_FAILED_DEXOPT 最新的ADT和android SDK在将jar文件生成dex文件时会合并类,为了标识类中的每一个方法,为每一个方法分配一个id,早期的android VM指令集使用sh

xpz445094213的博客 1085

金融机构和贷款产品数据抓取:使用Python爬虫技术获取金融机构的贷款产品信息与条件

本文介绍了如何使用Python爬虫技术抓取金融机构的贷款产品信息,包括静态网页抓取和动态网页抓取两种方法。通过requestsSelenium等工具,我们能够轻松抓取银行和消费金融平台上的贷款信息,并存储和分析数据。随着技术的发展,我们还可以扩展爬虫功能,抓取更多的金融机构网站,或者结合自然语言处理技术对贷款产品的评论进行情感分析,为用户提供更多维度的贷款决策支持。

2201_76125261的博客 1733

预防 Android Dex 64k Method Size Limit

感谢原文作者ingramchen分享 如果你有 Android App 持续开发一年以上,那你多半已经遇过很有名的 Dex 64k method 数量上限: Unable to execute dex: method ID not in [0, 0xffff]: 65536 Conversion to Dalvik format failed: Unable to execute d

猫的阁楼 2006

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

預防 Android Dex 64k Method Size Limit

如果你有 Android App 持續開發一年以上,那你多半已經遇過很有名的 Dex 64k method 數量上限: Unable to execute dex: method ID not in [0, 0xffff]: 65536 Conversion to Dalvik format failed: Unable to execute dex: method ID not in

xiechengfa的技术笔记 1774

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Android Studio 错误 com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536

第1步  添加依赖于你的build.gradle支持MultiDex库 dependencies { ... compile 'com.android.support:multidex:1.0.1' ... } 第2步  在buildType或productFlavor中开启multiDexEnabled。 defaultConfig { ... multiDexEnable

iblue007的博客 466

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

久仰的方法数超65k,终于遇到了

解决方案:http://blog.youkuaiyun.com/t12x3456/article/details/40837287 http://www.cnblogs.com/wingyip/p/4496028.html   前几天做电影音乐加入虾米的SDK就发现run不起来了,提示大概就是方法数超过了65000的问题。 eclipse提示是这样的: Unable to execute dex:

AoXiangDeFeiYing的专栏 898

LinearAlloc exceeded capacity Problem

在開發 Android App 的過程中,專案會因為功能需求引入一些 opensource 套件包、lib、jar等資源,當專案日益龐大,就有可能發生 LinearAlloc exceeded capacity 的問題。本篇就來簡單介紹一下原因以及可行的解決方法 首先,先簡單介紹 LinearAlloc LinearAlloc (線性分配器) source code:android_

xiechengfa的技术笔记 3430

Mutildex解决Android应用Dex方法数限制

作为一个Android开发者,在开发应用时,随着业务规模发展到一定程度,不断地加入新功能,添加新的类库,代码在急剧的膨胀,相应的APK包的大小也在相应地增加。那么可能有一天,你的应用会抛出这样一个error信息:Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536这

粤语伶仃的专栏 2549

Unable to execute dex: method ID not in [0, 0xffff]: 65536资料

預防 Android Dex 64k Method Size Limit 08 September 2014 如果你有 Android App 持續開發一年以上,那你多半已經遇過很有名的 Dex 64k method 數量上限: Unable to execute dex: method ID not in [0, 0xffff]: 65536 Conversion to Dal

Glory的专栏 2万+

关于 Android Dex 方法限制的一些总结

由于Android本身的一些原因,Android应用文件中的dex文件存在一个方法数目限制。随着App规模的越来越大,这个限制也成为一个比较头疼的问题。各位开发者为了解决这个问题也费了不少心思,Google官方也在为这个问题提出了一些解决方案。本文就这些情况做了一个总结。

penkzhou的技术博客 1437

Android Dex分包之旅

原文出处:http://yydcdut.com/2016/03/20/split-dex/ 当程序越来越大之后,出现了一个 dex 包装不下的情况,通过 MultiDex 的方法解决了这个问题,但是在底端机器上又出现了INSTALL_FAILED_DEXOPT 的情况,那再解决这个问题吧。等解决完这个问题之后,发现需要填的坑越来越多了,文章讲的是我在分包处理中填的坑,比如 65536、L

1145

升级应用编译SDK23版本的总结

在升级时, 调试使用命令: gradle clean; gradle build, 多次执行, 检验错误. Android 6.0 1. 替换Gradle 替换全部项目的Gradle配置, 使用版本号23. repositories { mavenCentral() maven { url "http://maven.chunyu.mobi/cont

idaretobe的专栏 1705

INSTALL_FAILED_DEXOPT LinearAlloc exceeded capacity

01-24 11:14:54.884: I/dalvikvm(12382): DexOpt: not resolving ambiguous class 'Lorg/apache/commons/codec/DecoderException;' 01-24 11:14:55.935: E/dalvikvm(12382): LinearAlloc exceeded capacity (5242880

吴海洋的专栏 3146

Handler 详解

这个详解基本小结了Handler的使用和相关的知识,在了解这些知识前,我们先来看看这些问题.Handler 是什么? 子线程更新UI有几种典型方式,这些方式本质上是什么样的? 子线程真的不能更新UI吗? HandlerThread是什么? 主线程和子线程之间如何相互通信? 好了,如果上面的问题,你能对答如流,并且深知其中的原理那么没有必要继续看下去了,反之,就该好好补补了(^o^)/~。Handle

Linroid的博客 6944

Android 绘制虚线

简单需求先来看看这么一个需求 水平虚线如果需要完成上面的水平虚线,可以这样处理。 声明shape,其中dashGap是虚线的间隔宽度,dashWidth是实线的间隔宽度,stroke翻译过来是名词,画 <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/and

Linroid的博客 3614
上一篇: Android 绘制虚线
下一篇: Android 在线热修复框架 AndFix 初步
linroidh
博客等级 码龄16年 15粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值