枚举与静态常量、内存占用

2022-09-02 21:45:03

首先,请参阅 Android 开发人员指南中的以下引用:

尽管在第一个项目符号中发出了不祥的警告,即“严格避免在Android上使用枚举”,但在这一点上所说的实际上听起来并不那么糟糕。常量是 32 位整数,枚举可能是 64 位引用。那里给出的关于枚举价格是两倍的数学是有道理的,而且似乎并不那么可怕。

我担心的是,这一警告可能部分地以第二个要点为基础。

我想知道一个简单的枚举“类”声明是否携带500字节的开销?eacn 枚举类型怎么样?

类型可以是“扩展类”似乎很合理,因为它们可以采用自己的方法,而不仅仅是实例。把它表述为一个问题,如果我的枚举是Color,并且我有20种Color枚举类型(例如红色,蓝色,绿色...),那么每种类型的枚举是500字节吗?


答案 1

枚举是Android世界中持续不断的无限争论。

你可以在这里听到罗曼·盖伊(Romain Guy)和切特·哈斯(Chet Haase)关于它的精彩演讲:http://www.parleys.com/play/5298f999e4b039ad2298c9e3/chapter57/about

根据这段视频,Dalvik中的物体有多大可以计算为:

overhead of Object + overhead of dlmalloc + data + align
  • 对象的开销正好是 8 个字节。
  • dlmalloc 的开销可以是 4 - 8 个字节(大多数情况下是 8 个字节)
  • 数据的大小取决于数据(当然)
  • 最后,所有内容都必须是 8 字节对齐的(例如,如果对象有 12 个字节,则需要 16 个字节)

请记住,枚举的每个值实际上都是枚举类的实例。

要记住的另一个要点是dex文件大小。例如,以下枚举大约需要 1,112 个字节

public static enum Things {
    THING_1,
    THING_2;
};

或者,您可以有两个静态 int,它们将占用 128 个字节。

public static int THING_1 = 1;
public static int THING_2 = 2;

dex 文件大小提高了 10 倍。

在生成多少编译的dalvik代码方面也有很大的不同。对于Enum,编译器为你做了很多事情。在运行时首次装入类时,将进行静态类初始化。它增加了启动时的加班时间。

另一方面,枚举也带来了很多优点:可读性,可用性,类型安全代码。我只会在特定的极端情况下担心枚举。

特别是当我们考虑到使用ProGuard可以优化枚举将它们转换为正常的int常量时。


答案 2

您错过了阅读消息。

您报价

Every class in Java (including anonymous inner classes) uses about 500 bytes of code.

请注意,您需要将类定义存储在某个位置,这需要 500 个字节。

这意味着 和 之间没有区别。enum Const {}class Const{}

更重要的是,创建实例时对象消耗了多少内存。

Every class instance has 12-16 bytes of RAM overhead.- 下一行表单源。

总结一下。只有当在同一长容器(枚举或类)中声明时,才能使 int 值的形式常量受益。

实际上,枚举也是一个扩展类型的类,它的实例比静态 int 常量需要更多的内存。Enum<?>

您在这里交易的是内存消耗和类型安全代码。当您使用int作为常量时,您无法保证类型安全。

public void doAction(int what) {}

public void doAction(What what) {}

在现代设备上,您可以编写消耗更多内存的代码。但是对于代码的某些方面可能更容易使用int对于其他枚举是正确的选择。这在androind R包上尤其明显,其中代码量很大。

在这种情况下,您应该将int用于小域字段枚举更安全。