. 使用 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. 流量加密之:MSF流量加密

    流量加密之:MSF流量加密 目录 流量加密之:MSF流量加密 1 背景 2 生成SSL证书 3 使用MSF生成带证书的后门 4 验证流量 1 背景 在MSF中生成shell,并上线运行时.都是通过ht ...

  2. .Net6 Html.Action无法使用(ViewComponents)

    接触了 net core的小伙伴们 已经发现 @html.Action()方法 官方已经不提供支持了,转而使用 ViewComponents替代了,同时也增加了TagHelper. 1.如果想用以前的 ...

  3. LRU 居然翻译成最近最少使用?真相原来是这样!(附力扣题解)

    前言 相信有很多同学和我一样,第一次碰到 LRU(Least Recently Used) 的这个解释「最近最少使用」都不知道是什么意思,用汤家凤老师的话来说: 我真的感到匪夷所思啊! 最近是表示时间 ...

  4. Java Agent场景性能测试分析优化经验分享

    摘要:本文将以Sermant的SpringBoot 注册插件的性能测试及优化过程为例,分享在Java Agent场景如何进行更好的性能测试优化及在Java Agent下需要着重注意的性能陷阱. 作者: ...

  5. Linux——CentOS7无法ping通外网问题

    出现问题: 当在终端中出现 ping: unknown host www.baidu.com 或 ping: www.baidu.com: 未知的名称或服务 时,该如何解决? 解决方法: 1.使用ro ...

  6. VMware-安装rpm包出现警告:tigervnc-1.1.0-24.el6.x86_64.

    警告:tigervnc-1.1.0-24.el6.x86_64. 解决方法:rpm -ivh tigervnc-1.1.0-24.el6.x86_64.rpm --force --nodeps --n ...

  7. 前端 ArrayBuffer 与 Blob 互转

    我们在使用ajax向后端发送请求时,responseType可以设置返回数据的格式,它支持的格式有"text"."arraybuffer"."blob ...

  8. Vue CLI 2内置框架webpack框架结构解析

    目前Vue已经到3.X版本,相应的Vue CLI也已经是Vue CLI 3版本,创建命令使用vue create,如果要用2.X版的vue init命令,需要全局安装一个桥接工具: npm insta ...

  9. CentOS 镜像官网下载链接

    CentOS 镜像官网下载链接: https://www.centos.org/download/mirrors/ http://mirrors.aliyun.com/centos/ https:// ...

  10. BDD测试和TDD测试

    BDD测试和TDD测试 TDD TDD是测试驱动开发(Test-Driven Development)的缩写,是敏捷开发中的一项测试技术,也是一种设计方法论.她的大概思路是:先针对每个功能点抽象出接口 ...