(枚举对内存及体积影响)注解的一个特殊使用场景

话不多说,最近在进行内存优化排查时,准备对枚举下手了,为什么呢?官方文档不建议我们用枚举:

Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android

枚举的局限

个人认为,使用枚举有两个弊端:
1.增加APK体积,对你没听错,我给你证明下。
2.增加APP运行时内存,虽然影响不大,只是一个细节点。

为啥说增加体积

1.创建一个java类如下:

public class EnumUtil {

    public  void  start(){
    }

    public enum  Demo{
        START,
        END,
        STOP
    }
}

然后执行Javac命令,编译为class文件。再通过以下命令执行,生成dex文件

dx --dex --output=需要生成dex的目录和名称   class文件所在的目录

上面的命令有两个比较坑的地方,不注意可能要折腾很久:
1.--output=XXXX 等号后面不要有空格,会报错
2.大概率会出现以下报错:

PARSE ERROR:
class name (EnumUtil$Demo) does not match path (/Users/zhouhao/Android/23DesignMode/app/src/main/java/com/example/a23designmode/EnumUtil$Demo.class)

我之前其实一直没遇到过,换电脑了后好像必现,处理方式,这时候只要在--dex 后面加上--no-strict 就可以了
如下:dx --dex --no-strict --output=XXXX YYY

public class EnumUtil {
    private final static int START = 1;
    private final static int END = 1;
    private final static int STOP = 1;

    public void start() {
    }

}

把上面的枚举代码替换为 静态常量如下,再执行上面打dex文件的命令,生成dex 文件。对比看下结果:


image.png

使用枚举时候,明显dex文件大了不少,几百个字节,仅仅一个简单的枚举,体积就大了不少,如果公司的项目 大量使用,APP体积应该是有不少优化空间。

为啥说增加了内存

增加内存的说法又是怎么来的?同样我们使用javap XXX.class 简单的查看下两种写法的字节码。反编译后看到枚举字节码如下:

public final class com.example.a23designmode.EnumUtil$Demo extends java.lang.Enum {
  public static final com.example.a23designmode.EnumUtil$Demo START;
  public static final com.example.a23designmode.EnumUtil$Demo END;
  public static final com.example.a23designmode.EnumUtil$Demo STOP;
  public static com.example.a23designmode.EnumUtil$Demo[] values();
  public static com.example.a23designmode.EnumUtil$Demo valueOf(java.lang.String);
  static {};
}

重点就是把每个枚举类型搞成一个个对象了,简单总结如下:

以64位操作系统,对象头中的Markword存 hashcode 、GC分代、锁状态标志就部分就8字节 ,指针压缩(指针作用是表明这个对象被那个类创建持有的)开启就是4不开启8字节 ,还有就是数组长度这部分只有数组对象才有。那至少就12个字节了,一个int类型的4字节!还不算上对其部分。

多提一句:为什么要对其:因为这个涉及到一个CPU的 缓存行污染

CPU的 缓存行污染

比如不对齐 一个缓存行大小假如8个字节,存放了A对象的6个字节,存放了B对象的2个字节,那么当A对象改变了,B对象在被CPU加载时候需要重新加载到缓存行中 因此影响执行效率

最优方案

上面说了一堆,还没说道重点。重点就是我们使用注解来替代枚举。并且还可以限制开发者传制定的值:

public class EnumUtil {
    private   static final int AAAA =1;
    private   static final int BBBB =2;
    public  void  start(@EnumType int type){
        
        //TODO:使用
//        start(111); //这样用户直接设置111这样,就会编译报错
        start(AAAA);
    }
    
    @Retention(RetentionPolicy.SOURCE)
    @Target(ElementType.PARAMETER)
    @IntDef({AAAA,BBBB})
    @interface EnumType{

    }
}

好处就是当开发者随意传递就编译报错,这个场景使用起来还是很不错的!

你可能感兴趣的:((枚举对内存及体积影响)注解的一个特殊使用场景)