NDK 减少 so 库体积方法总结
. 使用 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 库体积方法总结的更多相关文章
- 【Android】Eclipse自动编译NDK/JNI的三种方法
[Android]Eclipse自动编译NDK/JNI的三种方法 SkySeraph Sep. 18th 2014 Email:skyseraph00@163.com 更多精彩请直接访问SkySer ...
- 【Android】Eclipse自己主动编译NDK/JNI的三种方法
[Android]Eclipse自己主动编译NDK/JNI的三种方法 SkySeraph Sep. 18th 2014 Email:skyseraph00@163.com 一.Eclipse关联cy ...
- linux减少服务器带宽的方法
linux减少服务器带宽的方法用百度静态资源公共库http://cdn.code.baidu.com/ 不仅可以不使用服务器流量 而且还有cdn加速比方说http://apps.bdimg.com/l ...
- mac下使用glew库,方法
mac下使用glew库,方法 分类: OpenGL2015-01-15 15:52 210人阅读 评论(0) 收藏 举报 目录(?)[+] 主要参考http://www.cnblogs.com ...
- Xcode6.1标准Framework静态库制作方法。工程转Framework,静态库加xib和图片。完美解决方案。
http://www.cocoachina.com/bbs/read.php?tid-282490.html Xcode6.1标准Framework静态库制作方法.工程转Framework,静态库加x ...
- paip.ikanalyzer 重加载词库的方法.
paip.ikanalyzer 重加载词库的方法. 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn ...
- 详细地jsoncpp编译方法 和 vs2010中导入第三方库的方法
详细地jsoncpp编译方法 和 vs2010中导入第三方库的方法 一 编译链接 1 在相应官网下载jsoncpp 2 解压得到jsoncpp-src-0.5.0文件 3 打开jsoncpp-src- ...
- Android中集成第三方库的方法和问题
Android中集成第三方库的方法和问题 声明: 1. 本文參考了网上同学们的现有成果,在此表示感谢,參考资料在文后有链接. 2. 本文的重点在第三部分,是在开发中遇到的问题及解决的方法.第一,第二部 ...
- 用NDK调用第三方库
用NDK调用第三方库遇到不少坑,总结一下. 1.添加JNI目录 参考: http://www.cnblogs.com/lanqie/p/7442668.html 2.文件介绍: 其中:JniFacto ...
- golang 编译或链接 c语言动态、静态库的方法, golang 与 c语言 相互调用
1.golang链接c静态库的方法可以见这个示例: https://github.com/atercattus/go-static-link-example https://github.com/sh ...
随机推荐
- TNF拮抗剂的结构、功能与结核感染_Wallis2008
中信国健临床通讯 2009年第2期 TNF拮抗剂的结构.功能与结核感染 Robert S. Wallis. THE LANCET Infectious Diseases. 2008; 8:601–61 ...
- gdbOF阅读笔记
前言 今天阅读了一本说明书,<gdbOF: A Debugging Tool for OpenFOAM> 受himryangzz视频启发去读相关内容,在此对himryangzz表示感谢 希 ...
- Java处理正则匹配卡死(正则回溯问题)
目录 背景 项目现场问题 问题跟踪 优化方案 处理正则问题 使用子线程来匹配正则实现 监控线程实现 最优选择方案 参考文章 正则匹配卡死怎么来的? 背景 背景:这次问题的背景是项目上遇到了,在使用正则 ...
- 单一资产VAR风险--基于python
数据源:使用 AKShare包.它是一个免费.开源的 Python 财经数据接口包.网址https://www.akshare.xyz/index.html 一.获取数据: 计算日收益率: impor ...
- gmgo国密算法库
gmgo国密算法库 一.背景介绍 基于go1.17.5实现的国密算法库,包括: sm2 : 基于emmansun/gmsm的sm2部分实现部分扩展. sm3 : 基于emmansun/gmsm的sm3 ...
- PHP解密支付宝小程序的加密数据,手机号等。
1.小程序端代码示例 my.getPhoneNumber({ success: (res) => { let encryptedData = res.response; my.httpReque ...
- git手记
参照的是http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000这里的,git教程确实写得不 ...
- SFTP实现密钥登陆并上传文件
什么是SFTP,公开键认证,SFTP可不是FTP协议的扩展,他是基于SSH的文件传输协议. 而当SFTP服务器登录有客户端的公开键时,客户端就可以用自己的私有键去跟服务器握手(handshake)已实 ...
- x-sheet 开发系列教程:初始化配置
介绍 x-sheet 是一款高性能 Web JavaScript Canvas 电子表格,之前小编写过一篇 x-sheet 入门体验,简单介绍了一下如何使用 x-sheet.这次我们继续深入一下,了解 ...
- mybatis_pagehelper_selectOne的SQL语句被莫名的增加分页相关设置,暂定解决办法
在使用mybatis.以及其分页插件pagehelper时,原本的一个selectOne的sql语句被莫名(原因未知)的加上了分页相关,引起如下异常: exception is org.apache. ...