转载请标明出处:http://blog.csdn.net/shensky711/article/details/52329035

本文出自: 【HansChen的博客】

什么是64K限制和LinearAlloc限制

64K限制

随着Android应用功能的增加,代码量不断地增大,当应用方法数量超过了65536的时候,编译的时候便会提示:

这个Android著名的Dex 64k method数量上限。那么,是什么原因导致方法数不能超过64K呢?网上搜集了一下资料,原因一般有:

  1. DexOpt优化的限制:当Android系统启动一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt。DexOpt的执行过程是在第一次加载Dex文件的时候执行的。这个过程会生成一个ODEX文件,即Optimised Dex。执行ODex的效率会比直接执行Dex文件的效率要高很多。但是在早期的Android系统中,DexOpt有一个问题,也就是这篇文章想要说明并解决的问题。DexOpt会把每一个类的方法id检索起来,存在一个链表结构里面。但是这个链表的长度是用一个short类型来保存的,导致了方法id的数目不能够超过65536个。当一个项目足够大的时候,显然这个方法数的上限是不够的。尽管在新版本的Android系统中,DexOpt修复了这个问题,但是我们仍然需要对老系统做兼容
  2. dalvik bytecode的限制:因为 Dalvik 的 invoke-kind 指令集中,method reference index 只留了 16 bits,最多能引用 65535 个方法,参考链接:http://stackoverflow.com/questions/21490382/does-the-android-art-runtime-have-the-same-method-limit-limitations-as-dalvik/21492160#21492160http://source.android.com/devices/tech/dalvik/dalvik-bytecode.html

鉴于以上原因,在打包Android应用的时候,会对方法数做一个检测,当方法数超过了DexFormat.MAX_MEMBER_IDX(定义为0Xffff, 注意,这个不是Dex文件格式的限制,Dex文件中存储方法ID用的并不是short类型,无论最新的DexFile.h新定义的u4是uint32_t,还是老版本DexFile引用的vm/Common.h里定义的u4是uint32或者unsigned int,都不是short类型,特此说明)便报错

LinearAlloc限制

即使方法数没有超过65536,能正常编译打包成apk,在安装的时候,也有可能会提示INSTALL_FAILED_DEXOPT而导致安装失败,这个一般就是因为LinearAlloc的限制导致的。这个主要是因为Dexopt 使用 LinearAlloc 来存储应用的方法信息。Dalvik LinearAlloc 是一个固定大小的缓冲区。在Android 版本的历史上,LinearAlloc 分别经历了4M/5M/8M/16M限制。Android 2.2和2.3的缓冲区只有5MB,Android 4.x提高到了8MB 或16MB。当方法数量过多导致超出缓冲区大小时,也会造成dexopt崩溃

谷歌分包方案

谷歌提供了一个multiDex的分包方案,当方法数超过65536的时候,生成多个dex文件,把应用启动时必须用到的类和该类的直接引用类放到main dex中,把其他类放到second dex中。当应用启动之后,动态加载second dex,从而避免64k问题。使用Android Studio很容易实现分包方案:

  1. 在build.gradle中添加:multiDexEnabled true
  2. 加入依赖‘compile ‘com.android.support:multidex:1.0.1’’
  3. 让应用的Application类直接使用或者继承MultiDexApplication
  4. 如果你想使用自定义的Application,又不想继承MultiDexApplication,那么可以在attachBaseContext方法里执行MultiDex.install(base)

以上就是谷歌multiDex方案所需做的设置,通过配置multiDex,便可解决64k方法数限制

谷歌multiDex存在的问题

虽然谷歌的分包方案很简单,但是效果并不是那么好,谷歌本身也枚举了分包方案的缺点

  1. 如果在主线程中执行MultiDex.install,加载second dex,因为加载从dex是同步的,会阻塞线程,second dex太大的话,有可能导致ANR
  2. API Level 14之前,由于Dalvik LinearAlloc bug(问题22586,就是上文提到的LinearAlloc问题),很可能会出问题的
  3. 应用程序使用了multiedex配置的,会造成使用比较大的内存
  4. 对于应用程序比较复杂的,存在较多的library的项目。multidex可能会造成不同依赖项目间的dex文件函数相互调用,找不到方法

如何解决谷歌分包方案的问题

针对上面的问题,参考网上的一些解决方案,如美团、facebook、微信等,初步使用的解决方法如下:

  1. 第一次启动的时候,检测到未曾加载过second dex,那么启动欢迎页面(启动新的进程,原来进程进入阻塞等待,注意,此时不会发生ANR,因为已经不是前台进程了),在欢迎页面里面进行second dex的加载,加载完成后通知主线程继续
  2. 设定单个dex文件最大方法数为48000(经验值)而不是65536,避免内存问题
  3. 同上
  4. 控制程序逻辑,未曾加载完second dex之前,进入阻塞等待,直到加载完程序才往下走

下面是流程图:

Android最大方法数和解决方案的更多相关文章

  1. Android的方法数超过65535问题

    Under the Hood: Dalvik patch for Facebook for Android 先来看一段中文内容 Hack Dalvik VM解决Android 2.3 DEX/Line ...

  2. 彻底解决Android 应用方法数不能超过65K的问题

    作为一名Android开发者,相信你对Android方法数不能超过65K的限制应该有所耳闻,随着应用程序功能不断的丰富,总有一天你会遇到一个异常: Conversion to Dalvik forma ...

  3. Android大图片裁剪终极解决方案(上:原理分析)

    转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-)  http://my.oschina.net/ryanhoo/blog/86842 约几个月前,我正 ...

  4. Android 启动APP黑屏解决方案

    #Android 启动APP黑屏解决方案# 1.自定义Theme //1.设置背景图Theme <style name="Theme.AppStartLoad" parent ...

  5. Android开发——Android M(6.0) 权限解决方案

    Android开发--Android M(6.0) 权限解决方案 自从Android M(6.0)发布以来,权限管理相比以前有了很大的改变,很多程序员发现之前运行的好好的Android应用在Andro ...

  6. Android终端与服务器数据传输解决方案

    Android终端与服务器数据传输解决方案 Android终端三种与服务器传输方式:   Socket传输 WebService传输 Post/Get获取数据方式 网络实现条件 端口:指定 协议:TC ...

  7. 支持WEB、Android、IOS的地图解决方案

    转自原文 支持WEB.Android.IOS的地图解决方案 工具链 GIS工具集 OpenGeo Suite 包含PostGIS, GeoServer, GeoWebCache, OpenLayers ...

  8. Android工程方法数超过64k,The number of method references in a .dex file cannot exceed 64K.

    最近将一个老的Eclipse项目转到Android Studio后,用gradle添加了几个依赖,项目可以make,但是一旦run就报错 Error:The number of method refe ...

  9. Android开发各类常见错误解决方案

    本文属于个人平时项目开发过程遇到的一些问题,记录下来并总结解决方案,希望能帮到大家解决问题,有些问题的解决方案是在StackoverFlow上找到的,建议大家遇到问题多去上面找,基本上都能找到解决方案 ...

随机推荐

  1. Udp 异步通信(三)

    转自:https://blog.csdn.net/zhujunxxxxx/article/details/44258719 1)服务端 using System; using System.Colle ...

  2. Text 尺寸获取

    获取text在当前文本内容下应该尺寸: 宽度:text.preferredWidth 高度:text.preferredHeight

  3. SpringBoot与MybatisPlus整合之SQL分析插件(六)

    pom.xml: <dependency> <groupId>p6spy</groupId> <artifactId>p6spy</artifac ...

  4. 如何使用git上传代码

    首先在github 上创建好远程仓库,并拷贝仓库地址,接下来按照以下步骤:   1.打开命令行进入要上传的文件目录,初始化 git init  2. 建立远程仓库,git remote add ori ...

  5. 最全的access2013教程 access 2010教程 access 2007教程 Access 2003教程

    最全的access2013教程 access 2010教程 access 2007教程 Access 2003教程 都在这个access中国网站里 http://www.office-cn.net/o ...

  6. RobotFramework自动化测试框架-Selenium Web自动化(二)关于在RobotFramework中如何使用Selenium很全的总结(上)

    好久没有继续分享关于自动化测试相关的东西了,自动化在现今的测试领域已经越来越重要了,大部分公司在测试岗位招聘中都需要会相关的自动化测试知识.而 RobotFramework自动化测试框架 是自动化测试 ...

  7. NOIP模拟 31

    补坑 skyh又AK 赛时榜搜索我的姓: 下一条 ... 自闭了. (只是表达对B哥强烈的崇敬) (如果B哥介意我把名字贴出来请联系我删掉) T1一打眼,好像就一个gcd 康了眼大样例,觉得没啥问题 ...

  8. Linux\CentOS Tomcat 配置

    需要注意的是:安装 Tomcat 之前需要把 jdk 安装好. 一.下载安装包 - 安装可以在官网自行下载,下载 tar.gz 包便可. 二.解压缩: tar -zxvf apache-tomcat- ...

  9. nyoj 48-小明的调查作业(set)

    48-小明的调查作业 内存限制:64MB 时间限制:1000ms Special Judge: No accepted:15 submit:29 题目描述: 小明的老师布置了一份调查作业,小明想在学校 ...

  10. 【SpringBoot | Swagger】SpringBoot整合Swagger

    SpringBoot整合Swagger 1. 什么是Swagger Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.简单说就是项目跑起来了, ...