这里给大家推荐一个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]:
较高版本的Android构建系统的报错信息(Android 8.0)
trouble writing output:
Too many field references: ; max is
You may try using --multi-dex option.
注意:构建时期发生的错误哦
为什么会出现64K的限制呢?
一般排查问题我们需要从问题本身入手,那么log是最重要的信息。
在构建流程中出现这种问题,根据提示我们大概明白方法数过大,而这些方法是存在于编译后的
.class
文件中的,而
.class
最后要存在于dex文件中。
那么如此分析的话,问题应该存在于dex的打包流程当中,这个需要以后深入了解一下。
根据前人的一些分析,我们来看看MemberIdsSection文件。代码不多,如下:
/*
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 */
package com.android.dx.dex.file;
import com.android.dex.DexFormat;
import com.android.dex.DexIndexOverflowException;
import java.util.Formatter;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
28 * Member (field or method) refs list section of a {@code .dex} file.
29 */
public abstract class MemberIdsSection extends UniformItemSection {
/**
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 */
public MemberIdsSection(String name, DexFile file) {
super(name, file, );
}
/** {@inheritDoc} */
@Override
protected void orderItems() {
int idx = ;
if (items().size() > DexFormat.MAX_MEMBER_IDX + ) {
throw new DexIndexOverflowException(getTooManyMembersMessage());
}
for (Object i : items()) {
((MemberIdItem) i).setIndex(idx);
idx++;
}
}
private String getTooManyMembersMessage() {
Map<String, AtomicInteger> membersByPackage = new TreeMap<String, AtomicInteger>();
for (Object member : items()) {
String packageName = ((MemberIdItem) member).getDefiningClass().getPackageName();
AtomicInteger count = membersByPackage.get(packageName);
if (count == null) {
count = new AtomicInteger();
membersByPackage.put(packageName, count);
}
count.incrementAndGet();
}
Formatter formatter = new Formatter();
try {
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 + );
for (Map.Entry<String, AtomicInteger> entry : membersByPackage.entrySet()) {
formatter.format("%n%6d %s", entry.getValue().get(), entry.getKey());
}
return formatter.toString();
} finally {
formatter.close();
}
}
}
在48行到49中,我们看到如下可能抛出异常的情况
if (items().size() > DexFormat.MAX_MEMBER_IDX + ) {
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 + );
同时我们还要注意
DexFormat
类,
/**
* Maximum addressable field or method index.
* The largest addressable member is 0xffff, in the "instruction formats" spec as [email protected] or
* [email protected].
*/
public static final int MAX_MEMBER_IDX = ;
根据注释,我们来到Dalvik 字节码,根据表格中的解释如下图:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwQjMx8CX39CXy8CXycXZpZVZnFWbpN0NlAXayR3cvwFduVWay9WLvRXdh9CXyI3Zv1UZnFWbp9zZuBnLxE2Y0YWZlNGO1ImMjRGN50CM4IjM5UTMvw1cldWYtl2XkF2bsBXdvw1bp5SdoNnbhlmauMXZnFWbp1CZh9GbwV3Lc9CX6MHc0RHaiojIsJye.png)
可以看到类型索引(16 位),由此可以知道,无论是方法数还是字段数都不能超过65536,这也就是为什么在构建流程中出现65536的报错信息。
由此可以得出结论:
单个dex的方法或者字段数量不能超过65536
如何避免64K问题?涉及到dex分包的知识,同时也是涉及到APK瘦身优化等问题。
很多问题都需要我们去直面,一步步去解决。