Android为什么会有65536的方法数量限制

这里给大家推荐一个Android源码网站:http://androidxref.com/(无需翻墙)

前言

65536是什么样的数?2的16次方或者说64KB

下边这个error是不是很熟悉

较高版本的Android构建系统下的提示(Android 7.0及以下):

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

较高版本的Android构建系统的报错信息(Android 8.0)

trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.

注意:构建时期发生的错误哦

为什么会出现64K的限制呢?

一般排查问题我们需要从问题本身入手,那么log是最重要的信息。

在构建流程中出现这种问题,根据提示我们大概明白方法数过大,而这些方法是存在于编译后的.class文件中的,而.class最后要存在于dex文件中。

那么如此分析的话,问题应该存在于dex的打包流程当中,这个需要以后深入了解一下。

根据前人的一些分析,我们来看看MemberIdsSection文件。代码不多,如下:

1 /*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dx.dex.file;
18
19import com.android.dex.DexFormat;
20import com.android.dex.DexIndexOverflowException;
21
22import java.util.Formatter;
23import java.util.Map;
24import java.util.TreeMap;
25import java.util.concurrent.atomic.AtomicInteger;
26
27/**
28 * Member (field or method) refs list section of a {@code .dex} file.
29 */
30public abstract class MemberIdsSection extends UniformItemSection {
31
32    /**
33     * Constructs an instance. The file offset is initially unknown.
34     *
35     * @param name {@code null-ok;} the name of this instance, for annotation
36     * purposes
37     * @param file {@code non-null;} file that this instance is part of
38     */
39    public MemberIdsSection(String name, DexFile file) {
40        super(name, file, 4);
41    }
42
43    /** {@inheritDoc} */
44    @Override
45    protected void orderItems() {
46        int idx = 0;
47
48        if (items().size() > DexFormat.MAX_MEMBER_IDX + 1) {
49            throw new DexIndexOverflowException(getTooManyMembersMessage());
50        }
51
52        for (Object i : items()) {
53            ((MemberIdItem) i).setIndex(idx);
54            idx++;
55        }
56    }
57
58    private String getTooManyMembersMessage() {
59        Map<String, AtomicInteger> membersByPackage = new TreeMap<String, AtomicInteger>();
60        for (Object member : items()) {
61            String packageName = ((MemberIdItem) member).getDefiningClass().getPackageName();
62            AtomicInteger count = membersByPackage.get(packageName);
63            if (count == null) {
64                count = new AtomicInteger();
65                membersByPackage.put(packageName, count);
66            }
67            count.incrementAndGet();
68        }
69
70        Formatter formatter = new Formatter();
71        try {
72            String memberType = this instanceof MethodIdsSection ? "method" : "field";
73            formatter.format("Too many %1$s references to fit in one dex file: %2$d; max is %3$d.%n" +
74                            "You may try using multi-dex. If multi-dex is enabled then the list of " +
75                            "classes for the main dex list is too large.%n" +
76                    "References by package:",
77                    memberType, items().size(), DexFormat.MAX_MEMBER_IDX + 1);
78            for (Map.Entry<String, AtomicInteger> entry : membersByPackage.entrySet()) {
79                formatter.format("%n%6d %s", entry.getValue().get(), entry.getKey());
80            }
81            return formatter.toString();
82        } finally {
83            formatter.close();
84        }
85    }
86
87}

在48行到49中,我们看到如下可能抛出异常的情况

if (items().size() > DexFormat.MAX_MEMBER_IDX + 1) {
     throw new DexIndexOverflowException(getTooManyMembersMessage());
}

getTooManyMembersMessage()函数内(72行到77行)有如下异常信息字符串构造

String memberType = this instanceof MethodIdsSection ? "method" : "field";
           formatter.format("Too many %1$s references to fit in one dex file: %2$d; max is %3$d.%n" +
                            "You may try using multi-dex. If multi-dex is enabled then the list of " +
                            "classes for the main dex list is too large.%n" +
                    "References by package:",
                    memberType, items().size(), DexFormat.MAX_MEMBER_IDX + 1);

同时我们还要注意DexFormat类,

    /**
     * Maximum addressable field or method index.
     * The largest addressable member is 0xffff, in the "instruction formats" spec as field@CCCC or
     * meth@CCCC.
     */
   public static final int MAX_MEMBER_IDX = 0xFFFF;

根据注释,我们来到Dalvik 字节码,根据表格中的解释如下图:

Dalvik

可以看到类型索引(16 位),由此可以知道,无论是方法数还是字段数都不能超过65536,这也就是为什么在构建流程中出现65536的报错信息。

由此可以得出结论:

单个dex的方法或者字段数量不能超过65536

如何避免64K问题?涉及到dex分包的知识,同时也是涉及到APK瘦身优化等问题。

很多问题都需要我们去直面,一步步去解决。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,265评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,274评论 1 288
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,087评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,479评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,782评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,218评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,594评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,316评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,955评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,274评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,803评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,177评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,732评论 3 229
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,953评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,687评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,263评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,189评论 2 258

推荐阅读更多精彩内容