. 使用 strip

使用 NDK toolchain 可以把调试的 C++ 符号表(Symbol Table)中数据删除,我们一般我们打成 APK 会自动帮我们做这个工作,当然也可以手动设置:

手动的在链接选项中加入 strip 参数,配置如下所示:

SET_TARGET_PROPERTIES(yoga PROPERTIES LINK_FLAGS "-Wl,-s")

也可以手动执行 ndk 提供的aarch64-linux-android-strip命令移除动态库中的调试信息,这种方式除了前面方法外优化体积最高的方式,比如 libLibSampleApp.so 从 48M 直接优化到了 992k。

. 设置编译器的优化 flag

编译器有个优化 flag 可以设置,分别是-Os(体积最小),-O3(性能最优)等。这里将编译器的优化 flag 设置为-Os,以便减少体积。

CMake:

set(CMAKE_C_FLAGS "\({CMAKE_C_FLAGS} -Os")
set(CMAKE_CXX_FLAGS "\){CMAKE_C_FLAGS}")

Android.mk

LOCAL_CPPFLAGS += -Os

LOCAL_CFLAGS += -Os

除了直接删除占用体积较大的模块外,编译器优化是排下来优化空间最大的方法。设置完-Os后占用提交较大的前几个库体积对比:

. 使用 gc-sections 去除没有用到的函数

有些时候代码量比较大的时候我们没办法手动发现无用的函数,这个时候可以可以开启编译器的 gc-sections 选项,让编译器自动的帮你做到这一点。

编译器可以配置自动去除未使用的函数和变量,以下是配置方式:

CMake:

去除未使用函数与变量

set(CMAKE_C_FLAGS "\({CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
set(CMAKE_CXX_FLAGS "\){CMAKE_C_FLAGS}")

设置去除未使用代码的链接flag

SET_TARGET_PROPERTIES(yoga PROPERTIES LINK_FLAGS "-Wl,--gc-sections")

Android.mk:

OCAL_CPPFLAGS += -ffunction-sections -fdata-sections

LOCAL_CFLAGS += -ffunction-sections -fdata-sections

LOCAL_LDFLAGS += -Wl,--gc-sections

. 设置编译器的 Visibility Feature

Visibility Feature 就是用来控制在哪些函数可以在符号表中被输入,由于 C++并不是完全面向对象的,非类的方法并没有 public 这种修饰符,因此,要用 Visibility Feature 来控制哪些函数可以被外部调用。而 JNI 提供了一个宏-JNIEXPORT 来控制这点。所以只要对函数加上这个宏,像这样:

// JNIEXPORT就是控制可见的宏

// JNICALL在NDK这里没有什么意义,只是个标识宏

JNIEXPORT void JNICALL Java_ClassName_MethodName(JNIEnv *env, jobject obj, jstring javaString)

然后在编译器的 FLAGS 选项开启 -fvisibility = hidden 就可以。这样,不仅可以控制函数的可见性,并且可以减少包体的大小。

. 去除 C++代码中的 iostream 等直接 IO 相关代码

使用 STL 中的 iostream 相关库会明显的增加包的体积,而 Android 本身是有预编译库(android/log.h)可以代替输入到控制台的工具的。在我们的 SDK 中由于之前是控制台程序所以用到了输入输出,编译的时候没有把这块排除出去,造成了一定的体积冗余。

. STL 的使用方式

对于 C++的 library,引用方式有 2 种:

静态方式(static)

动态方式(shared)

其中,静态方式在编译时会将用到的相关代码直接复制到目的文件中;而动态方式则会将相关的代码打成 so 文件,以便多次引用。由于编译器在编译时并不能知道所有被引用的地方,所以同时会打入了很多不相关的代码。

所以,如果项目中引用 library 的函数较多时,用动态方式可以避免多次拷贝,节省空间。相反,则直接使用静态方式会更节省空间。由于我们 SDK 的模块特别多,再加上整体 APK 里面已经有其他业务引入了动态库,所以我们用动态库的方式。

. 不使用 Exception 和 RTTI

关于这两点在网上看到的没有实践过,不过拿过来可以作为包体积持续优化的参考。

  • RTTI

    通过 RTTI,能够通过基类的指针或引用来检索其所指对象的实际类型,即运行时获取对象的实际类型。C++通过下面两个操作符提供 RTTI。

    (1)typeid:返回指针或引用所指对象的实际类型。

    (2)dynamic_cast:将基类类型的指针或引用安全的转换为派生类型的指针或引用。

    RTTI 的选项是默认关闭的的,而代码中其实并没有用到相关的功能,这里可以直接关闭。
  • Exception

    使用 C++的 exception 会增加包的大小,而目前 JNI 对 C++的 exception 的支持是有 bug 的,比如下面这段代码就会引起程序的 crash(对于低版本的 android NDK)。因此要在程序中引入 exception 要自己实现相关逻辑,但是这样又会增加包体大小。对于开发者来说,exception 可以帮助快速定位问题,而对于使用者并不是那么重要,这里可以去掉。

NDK 减少 so 库体积方法总结的更多相关文章

  1. 【Android】Eclipse自动编译NDK/JNI的三种方法

    [Android]Eclipse自动编译NDK/JNI的三种方法 SkySeraph Sep. 18th  2014 Email:skyseraph00@163.com 更多精彩请直接访问SkySer ...

  2. 【Android】Eclipse自己主动编译NDK/JNI的三种方法

    [Android]Eclipse自己主动编译NDK/JNI的三种方法 SkySeraph Sep. 18th  2014 Email:skyseraph00@163.com 一.Eclipse关联cy ...

  3. linux减少服务器带宽的方法

    linux减少服务器带宽的方法用百度静态资源公共库http://cdn.code.baidu.com/ 不仅可以不使用服务器流量 而且还有cdn加速比方说http://apps.bdimg.com/l ...

  4. mac下使用glew库,方法

    mac下使用glew库,方法 分类: OpenGL2015-01-15 15:52 210人阅读 评论(0) 收藏 举报   目录(?)[+]   主要参考http://www.cnblogs.com ...

  5. Xcode6.1标准Framework静态库制作方法。工程转Framework,静态库加xib和图片。完美解决方案。

    http://www.cocoachina.com/bbs/read.php?tid-282490.html Xcode6.1标准Framework静态库制作方法.工程转Framework,静态库加x ...

  6. paip.ikanalyzer 重加载词库的方法.

    paip.ikanalyzer 重加载词库的方法. 作者Attilax  艾龙,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blog.csdn ...

  7. 详细地jsoncpp编译方法 和 vs2010中导入第三方库的方法

    详细地jsoncpp编译方法 和 vs2010中导入第三方库的方法 一 编译链接 1 在相应官网下载jsoncpp 2 解压得到jsoncpp-src-0.5.0文件 3 打开jsoncpp-src- ...

  8. Android中集成第三方库的方法和问题

    Android中集成第三方库的方法和问题 声明: 1. 本文參考了网上同学们的现有成果,在此表示感谢,參考资料在文后有链接. 2. 本文的重点在第三部分,是在开发中遇到的问题及解决的方法.第一,第二部 ...

  9. 用NDK调用第三方库

    用NDK调用第三方库遇到不少坑,总结一下. 1.添加JNI目录 参考: http://www.cnblogs.com/lanqie/p/7442668.html 2.文件介绍: 其中:JniFacto ...

  10. golang 编译或链接 c语言动态、静态库的方法, golang 与 c语言 相互调用

    1.golang链接c静态库的方法可以见这个示例: https://github.com/atercattus/go-static-link-example https://github.com/sh ...

随机推荐

  1. Vulhub 漏洞学习之:Drupal

    Vulhub 漏洞学习之:Drupal 目录 Vulhub 漏洞学习之:Drupal 1 Drupal < 7.32 "Drupalgeddon" SQL注入漏洞(CVE-2 ...

  2. window 运行 jar包方式

    所有文件 1.将jar包指定为bat批处理文件,然后可以双击启动 新建start2.txt 编辑保存一下内容,修改start2.txt后缀为bat,点击运行(此方法当前命令窗口关闭后,程序也关闭) j ...

  3. ABP微服务学习系列-修复System.Text.Json不支持序列化Exception

    前面我们已经把服务都启动了,然后我们试试请求API.发现请求出现500 返回错误 System.NotSupportedException: Serialization and deserializa ...

  4. Python算法教程_中文版书籍 程序员必备 免费下载

    Python算法教程_中文版免费下载地址 提取码:55kh 内容简介  · · · · · · 本书用Python语言来讲解算法的分析和设计.本书主要关注经典的算法,但同时会为读者理解基本算法问题和解 ...

  5. C - Functions again CodeForces - 789C (dp、思维)

    C - Functions again CodeForces - 789C #include<iostream> #include<cstdio> #include<cm ...

  6. 2021.09 ccf csp 第四题 收集卡牌

    2021.09 ccf csp 第四题 收集卡牌 思路 这题如果直接计算,因为不同的分类种数太多,枚举所有的分类情况是一个几乎不可能的复杂任务. 但不同摸牌次数,不同已摸出牌种类的子问题的答案之间,具 ...

  7. SDN实验环境安装

  8. 10. watch的实现原理

    watch的实现原理 watch和computed一样, 也是基于 Watcher 的 组件内部使用的watch 和 外部使用的 vm.$watch()都是调用的Vue.prototype.$watc ...

  9. Unity打包发布PC程序之——默认管理员权限运行

    https://blog.csdn.net/x1017619024/article/details/103970708

  10. CentOS7下MySQL数据的导入和导出

    一.数据导入 (1)进入mysql [root@localhost mysql]# mysql -u root -p (2)转到对应数据库下 mysql> use zenith_star; (3 ...