zoukankan      html  css  js  c++  java
  • 关于Android方法数量限制的问题

    限制Android方法数量的原因是:


    Android应用以DEX文件的形式存储字节码文件,在Dalvik字节码规范里,方法引用索引method referenceindex只有16,65536个。

     

    Op & Format

    Mnemonic / Syntax

    Arguments

    6e..72 35c

    invoke-kind {vC, vD, vE, vF, vG}, meth@BBBB

    B: method reference index (16 bits)

     

     

    注意是method reference,这里限制的是自己代码、Android框架、第三方库三者方法数量的总和。

     

    dex里方法只能索引65536个,但是报错不在这里。Android打包dex的过程如下:


    //Main.Java

    -> main() -> run() ->不分包执行runMonoDex()(或者分包执行runMultiDex())-> writeDex()

    // DexFile

    ->toDex() -> toDex0()

    // MethodIdsSection extends MemberIdsSection extends UniformItemSection extends  Section

    ->Section 的prepare() -> UniformItemSection的prepare0() ->MemberIdsSection的orderItems() -> getTooManyMembersMessage()

    //Main.java

    ->getTooManyIdsErrorMessage()

     

    MemberIdsSection里执行了这么一段代码

     protected void orderItems() {

            int idx = 0;

     

            if (items().size() >DexFormat.MAX_MEMBER_IDX + 1) {

                throw newDexIndexOverflowException(getTooManyMembersMessage());

            }

     

            for (Object i : items()) {

                ((MemberIdItem) i).setIndex(idx);

                idx++;

            }

        }

    getTooManyMembersMessage核心代码如下:构建了错误信息字符串。

    private String getTooManyMembersMessage() {

                 try {

                String memberType = this instanceofMethodIdsSection ? "method" : "field";

                formatter.format("Too many %s references:%d; max is %d.%n" +

                       Main.getTooManyIdsErrorMessage() + "%n" +

                        "References bypackage:",

                        memberType, items().size(),DexFormat.MAX_MEMBER_IDX + 1);

                return formatter.toString();

            }

        }

    }

     

    可见代码里检测了方法数量的上限,超过就会报错。这里的限制DexFormat.MAX_MEMBER_IDX

    出自

    public final classDexFormat {

      /**

         * Maximum addressable field or methodindex.

         * The largest addressable member is0xffff, in the "instruction formats" spec as field@CCCC or

         * meth@CCCC.

         */

        public static final int MAX_MEMBER_IDX =0xFFFF;

    }

    因此方法不能超过65536。这里的根源还是在dex字节码规范里方法引用索引的限制,但是强制报错是在这里限制的。

    另外,域的数量也有此限制。

     

    错误信息:

    Error:Errorconverting bytecode to dex:

    Cause:com.android.dex.DexIndexOverflowException:field ID not in [0, 0xffff]: 65536(笔者开发时遇到的是域数量问题,方法数量问题错误信息于此类似)

    :XXXXXX:transformClassesWithDexForDebug FAILED

    Error:Executionfailed for task ':XXXXXX:transformClassesWithDexForDebug'.

    >com.android.build.api.transform.TransformException:com.android.ide.common.process.ProcessException:java.util.concurrent.ExecutionException:com.android.ide.common.process.ProcessException:org.gradle.process.internal.ExecException: Process 'command 'C:ProgramFilesJavajdk1.8.0_73injava.exe'' finished withnon-zero exit value 2

    解决方法:

    Google官方出的分包方案,采用MultiDex支持库

    1,配置building.gradle,开启MultiDex

      

    android {

     

        defaultConfig {

            multiDexEnabled true

        }

    }

    dependencies{

        compile'com.android.support:multidex:1.0.0'

    }

     

    2,配置应用

    方法1:在AndroidManifest.xml的application中声明android.support.multidex.MultiDexApplication;

    <?xmlversion="1.0" encoding="utf-8"?>

    <manifestxmlns:android="http://schemas.android.com/apk/res/android"

       package="com.example.android.multidex.myapplication">

        <application

            ...

           android:name="android.support.multidex.MultiDexApplication">

            ...

        </application>

    </manifest>

    方法2让你自己的Application类继承MultiDexApplication

    方法3:让你自己的Application类重写attachBaseContext 方法,

    @Override

    protected voidattachBaseContext(Context base) {

    super.attachBaseContext(base);

    MultiDex.install(this);

    }

     

    其他错误情况:

    Error:java.lang.OutOfMemoryError: Java heap space.

    Please assign morememory to Gradle in the project's gradle.properties file.

    For example, thefollowing line, in the gradle.properties file, sets the maximum Java heap sizeto 1,024 MB:

    <em>org.gradle.jvmargs=-Xmx1024m</em>

    :XXXXXX:transformClassesWithDexForDebugFAILED

    Error:Executionfailed for task ':XXXXXX:transformClassesWithDexForDebug'.

    >com.android.build.api.transform.TransformException: java.lang.RuntimeException:com.android.ide.common.process.ProcessException:java.util.concurrent.ExecutionException:com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException:Process 'command 'C:Program FilesJavajdk1.8.0_73injava.exe''finished with non-zero exit value 3

     

    解决方法:

    Building.gradle

       dexOptions {

            javaMaxHeapSize "4g"

        }

     

    javaMaxHeapSize对应正则表达式是"\d+[kKmMgGtT]?"4g指4G字节。

    DexOptions类包含了获取JavaMaxHeapSize的方法,对应Building.gradle里dexOptions设置的javaMaxHeapSize。


    参考:

    http://source.android.com/devices/tech/dalvik/dalvik-bytecode.html

    http://jayfeng.com/2016/03/10/%E7%94%B1Android-65K%E6%96%B9%E6%B3%95%E6%95%B0%E9%99%90%E5%88%B6%E5%BC%95%E5%8F%91%E7%9A%84%E6%80%9D%E8%80%83/

    http://developer.android.com/intl/es/tools/building/multidex.html

  • 相关阅读:
    synchronized锁升级的过程(偏向锁到轻量锁再到重量级锁)转
    sprin 事务注解@Transactional的实现原理(转)
    springboot + redis + 注解 + 拦截器 实现接口幂等性校验(转)
    JAVA-TCP
    oracle查看连接信息
    C# 计算两个字符的相似度
    Java设计模式桥接模式
    C# Newtonsoft.Json.JsonReaderException:“Could not convert string to decimal:
    java设计模式结构型模式
    Java设计模式原型模式
  • 原文地址:https://www.cnblogs.com/ldq2016/p/6640807.html
Copyright © 2011-2022 走看看