【发布时间】:2016-12-04 13:10:59
【问题描述】:
我想知道用本机 C++ 编写的方法是否为了 Dex 方法计数限制而计入 Dex 文件方法计数中。
如果是,如果添加 1 个本机方法,则在 Dex 计数中添加多少方法?
Java 方法在 dex 计数中添加了多少方法,因为我似乎在我所做的每个构建中都没有一个可靠的数字...
【问题讨论】:
标签: java android c++ android-ndk java-native-interface
我想知道用本机 C++ 编写的方法是否为了 Dex 方法计数限制而计入 Dex 文件方法计数中。
如果是,如果添加 1 个本机方法,则在 Dex 计数中添加多少方法?
Java 方法在 dex 计数中添加了多少方法,因为我似乎在我所做的每个构建中都没有一个可靠的数字...
【问题讨论】:
标签: java android c++ android-ndk java-native-interface
要获得答案,我们应该通过.Dex Format。在我们的例子中,最有趣的部分是 method_ids 数组:
方法标识符列表。这些是所有方法的标识符 此文件所引用的,无论是否在文件中定义。这 列表必须排序,其中定义类型(由
type_id索引)是 主要顺序,方法名称(由string_id索引)是中间 顺序,方法原型(由proto_id索引)是次要顺序。 该列表不得包含任何重复的条目。
尽管数组记录的数量存储为 32 位无符号整数(参见 method_ids_size 字段),但实际上该数组不能包含超过 65536 的条目。这是因为invoke-xxxx dex 指令的method_id 操作数是一个16 位实体,并且必须是method_ids 的有效索引。作为索引大于65535 的结果记录将无法被字节码访问。所有这些都导致了众所周知的“64K 方法”问题。
因此,正如文档所说 - method_ids 对每个由该 dex 定义的方法以及外部方法都有一个记录,这些记录由已定义方法的代码引用。
因此,每次添加如下代码时:
public native void foo();
到您的一门课程 - 您在 method_ids 中获得了额外的记录。对于 abstract 方法的声明也是如此。然后,每次添加一些常规方法的实现,例如:
public void baz() {
/* ... */
}
您将获得baz() 本身的一条新记录以及baz() 引用但尚未添加到method_ids 的所有方法的记录。
本机代码对dex 内容完全没有影响,因为所有 C/C++ 源代码都编译为机器代码,通过 .so 文件分发。这些使用ELF格式,有其自身的局限性,完全独立于DEX。
【讨论】: