1.因为分析只在单个方法内分析,针对 Log 方法封装的情况,必须需要配置封装方法作为目标方法,才能删除完全删除,比如下面的方法需要配置 AccountLog.d 才能删除其调用处的 StringBuilder 创建 。
object AccountLog {@JvmStaticfun d(tag: String, msg: String) = Log.d(tag, msg)}
2.可能会误删除一些有用的指令,因为无法认为 Log.i 的两个参数的构建指令都是没有用的,我们只能确定 StringBuilder 的创建是没用的,但是一些其他的方法调用可能会改变一些对象的状态,因此存在一定风险 。Proguard 方案在我们上述方案在线上运行一年之后,尝试针对上述弊端进行优化,然后发现 proguard 还提供了 assumenoexternalsideeffects 指令,它可以让我们指定没有任何外部副作用的方法 。
指定了以后,它只会修改调用这个方法的实例本身,但不会修改其他的对象 。通过如下的配置可以删除无用的 StringBuilder 创建 。
-assumenoexternalsideeffects class java.lang.StringBuilder {public java.lang.StringBuilder();public java.lang.StringBuilder(int);public java.lang.StringBuilder(java.lang.String);public java.lang.StringBuilder append(java.lang.Object);public java.lang.StringBuilder append(java.lang.String);public java.lang.StringBuilder append(java.lang.StringBuffer);public java.lang.StringBuilder append(char[]);public java.lang.StringBuilder append(char[], int, int);public java.lang.StringBuilder append(boolean);public java.lang.StringBuilder append(char);public java.lang.StringBuilder append(int);public java.lang.StringBuilder append(long);public java.lang.StringBuilder append(float);public java.lang.StringBuilder append(double);public java.lang.String toString();}-assumenoexternalreturnvalues public final class java.lang.StringBuilder {public java.lang.StringBuilder append(java.lang.Object);public java.lang.StringBuilder append(java.lang.String);public java.lang.StringBuilder append(java.lang.StringBuffer);public java.lang.StringBuilder append(char[]);public java.lang.StringBuilder append(char[], int, int);public java.lang.StringBuilder append(boolean);public java.lang.StringBuilder append(char);public java.lang.StringBuilder append(int);public java.lang.StringBuilder append(long);public java.lang.StringBuilder append(float);public java.lang.StringBuilder append(double);}
不过,这个配置只适用于 Log 里只传入 String 的情况 。如果是int Log.w (String tag, Throwable tr)这种情况,就无法把Throwable参数也一起去掉 。那还是应该采用我们自己实现的插件才能优化干净 。此优化对抖音包体积收益,约为 520KB 。短方法内联上面介绍的两个优化是从去除无用的指令的角度出发,开篇 DEX 优化思路中我们有讲过,减少定义方法或者字段数从而减少 DEX 数量也是我们常用优化思路之一,短方法内联就是精简代码指令的情况下,同时减少定义方法数 。
在和海外竞品的对比过程中,我们发现单个 DEX 文件中的定义方法数远比竞品要多,进一步对 DEX 进行分析,发现抖音的 DEX 中有大量的 access,getter-setter 方法,而竞品中几乎没有 。因此我们打算针对短方法做一些内联优化,减少定义方法数 。
在介绍优化方案前,先来了解下内联的基础知识,内联作为最常见的代码优化手段,被称为优化之母 。一些语言像 C++、Kotlin 提供了 inline 关键字给程序员做函数的内联,而 Java 语言本身并没有给程序员提供控制或建议 inline 的机会,甚至 javac 编译过程中也没有做方法内联 。为了便于理解,我们通过一个简单的例子来看内联是如何工作的,如下代码中 callMethod 调用 print 函数:
public class InlineTest {public static void callMethod(int a) {int result = a + 5;print(result);}public static void print(int result) {System.out.println(result);}}
在内联之后 inlineMethod 的内容直接被展开到 callMethod 中, 从字节码的角度看变化如下:内联前:
public static void callMethod(int);Code:0: iload_01: iconst_52: iadd3: istore_14: iload_15: invokestatic#2// Method print:(I)V8: return
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Android WebRTC 对 AudioRecord 的使用
- TikTok/国际版抖音/海外版抖音2万字干货教程,新手必看
- 作为Android开发,这个知识点一定要知道,官方也改了 2 次
- Android logcat日志封装
- 抖音防烧屏脚本 – Tasker 脚本分享,适用于 OLED 屏幕
- Android开发:使用Kotlin+协程+自定义注解+Retrofit的网络框架
- Android开发:当前项目以Module形式引用别的项目的步骤
- Android恶意木马伪装成游戏APP,通过华为AppGallery分发
- 2021年Android开发新技术动向,未来的路该怎么走?
- Uni-app离线打包Android APK详细教程