Android NDK 如何缩减库的大小
来源:互联网 发布:方正证券--软件下载 编辑:程序博客网 时间:2024/05/24 01:50
Android NDK 如何缩减库的大小
Android NDK: how to reduce library size (translate from:link)
当我们刚开始做Algolia的android开发时,二进制文件的大小并不是我主要关注的。事实上我们一开始用的是java,后来出于性能的压迫下才换成了C/C++
后来要在AVelov(一个android应用)中集成我们的库时,才发现这货太大了:850KB,而AVelov整个app才638k!这就意味着AVelov要翻倍的趋势啊
后来我们将Algolia从850KB减小到了307KB,下面就来分享一下我们所做的东西吧
不用exceptions和RTTI
实际上在我们的底层库中我们没有使用异常,鉴于论述完整性,我也把exceptions一起说了
C++ exceptions 和RTTI默认是关闭的,可以通过设置在Application中设置APP_CPPFLAGS可以打开它,赠送一个使用共享的STL:
APP_CPPFLAGS += -fexceptions -frttiAPP_STL := stlport_shared
同时使用exceptions和RTTI可能,会显著增加你的binary size,这货能删就删吧,不要手软。还有另外一个避免使用C++exceptions的原因:C++对异常的支持不够好。例如:在jni层根本不可能catch一个C++exceptions然后再启动一个java异常。下面的code将会crash(将来的NDK toolchain可能会fix,说这话是2013/1/10):
try { ...}catch () { env->ThrowNew(env->FindClass("java/lang/Exception"), "Error occured");}
不用iostream
当我们接到Cyril的反馈,开始想办法减小library size时,我们发现最后一次提交后我们的库直接从850KB涨到了1.35M(此处有大汗!)。首先我们就怀疑是NDK toolchain更新导致的,随之用两个版本就测了一把,发现变化微乎其微。
当我们用二分法回溯commit历史时,逮住了罪魁祸首:std::cerr << .... << std::endl;
只是这一行就引进了C++的iostream,经我们测试发现如果用了iostream至少会增加300KB。所以用__android_log_print
替换吧:
#include <android/log.h>#define APPNAME "MyApp"__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "The value of 1 + 1 is %d", 1+1);
tips: 需要在Android.mk中加上:LOCAL_LDLIBS := -llog
使用 -fvisibility=hidden
一个非常有效的减小library是使用gcc的visibility feature。这个特性可以让你控制导出在符号表中的函数。jni自带了一个JNIEXPORT的可以标志公开函数的宏。所以需要确认所有的需要导出的函数都有JNIEXPORT:
JNIEXPORT void JNICALL Java_ClassName_MethodName(JNIEnv *env, jobject obj, jstring javaString)
也可以自定义JNIEXPORT:#define JNIEXPORT __attribute__ ((visibility ("default")))
然后需要在Android.mk中加入:
LOCAL_CPPFLAGS += -fvisibility=hiddenLOCAL_CFLAGS += -fvisibility=hidden
用了这一招之后library已经减小到809KB(-5%),可能根据project的不同略有差别。
用gc-section抛弃不用的函数
这招可以彻底的缩减library的size,直接砍掉了所有没有用途的函数。怎么使用呢,在Android.mk修改C和C++编译选项,请看:
LOCAL_CPPFLAGS += -ffunction-sections -fdata-sectionsLOCAL_CFLAGS += -ffunction-sections -fdata-sectionsLOCAL_LDFLAGS += -Wl,--gc-sections
这个优化选项只减少了1%(此处又有汗Σ( ° △ °|||)︴)
but如果以上选项贴加在一起,这下就超级牛X了:
LOCAL_CPPFLAGS += -ffunction-sections -fdata-sections -fvisibility=hiddenLOCAL_CFLAGS += -ffunction-sections -fdata-sections -fvisibility=hiddenLOCAL_LDFLAGS += -Wl,--gc-sections
直接减少到了691KB(-18.7%)
删除多余的代码
用-icf=safe链接选项就可以。但是要注意这招有副作用:有可能移除了内联函数,从而影响程序的性能。
在mips架构上没有这个指令,需要在Android.mk上加判断:
ifneq ($(TARGET_ARCH), mips) LOCAL_LDFLAGS += -Wl,--gc-sectionselse LOCAL_LDFLAGS += -Wl,--gc-sections,--icf=safeendif
这一步减少了0.8%,所有目前操作共减小到了687KB(-19.2%)
改变toolchain的默认选项
如果你想缩减的更彻底,那就需要修改默认编译选项了。这些编译选项因架构而异,例如:
在arm架构上inline-limit设置到64,x86/mips就是300;arm优化flags设置到-Os(size最优),x86/mips上则要设置为-O2(性能最优)。
由于arm事多力广,我们直接使用了arm配置。下面就是在android toolchain(version r8d)我们使用配置选项:
--- android-ndk-r8d/toolchains/mipsel-linux-android-4.6/setup.mk+++ android-ndk-r8d.new/toolchains/mipsel-linux-android-4.6/setup.mk@@ -41,12 +41,12 @@ TARGET_C_INCLUDES := $(SYSROOT)/usr/include-TARGET_mips_release_CFLAGS := -O2 +TARGET_mips_release_CFLAGS := -Os -g -DNDEBUG -fomit-frame-pointer -funswitch-loops - -finline-limit=300+ -finline-limit=64 TARGET_mips_debug_CFLAGS := -O0 -g --- android-ndk-r8d/toolchains/x86-4.6/setup.mk+++ android-ndk-r8d.new/toolchains/x86-4.6/setup.mk@@ -39,13 +39,13 @@ TARGET_CFLAGS += -fstack-protector-TARGET_x86_release_CFLAGS := -O2 +TARGET_x86_release_CFLAGS := -Os -g -DNDEBUG -fomit-frame-pointer -fstrict-aliasing -funswitch-loops - -finline-limit=300+ -finline-limit=64 # When building for debug, compile everything as x86. TARGET_x86_debug_CFLAGS := $(TARGET_x86_release_CFLAGS)
这次使用这些新的flags又缩减了8.5%,和之前的累加在一起减少到了613KB(-27.9%)
限制架构的数量
我们的最终建议是减少支持的架构。如果你有大量的浮点计算出于性能考虑就需要支持armeabi-v7a,但是如果你不需要一个FPU,armeabi也会给出一个近似的结果。然而对于mips处理器...现在市场上还没有用武之地呢~
如果binary size真的对你很重要,你可以只支持armeabi和x86架构(Application.mk):APP_ABI := armeabi x86
看到了没?砍掉了两个架构,我们的library一下变成了307KB,获得了64%的缩减,这还没有算上iostream增大的1.35M,O(∩_∩)O哈哈~
结论
希望这篇短文能够帮助你缩减android native libraries,毕竟android ndk的默认选项优化的太差了。但是也不要期望和我一样的减幅,这些操作都是因机而异,因code而异的。如果你有其他的缩减binary方法,在评论中分享出来吧!
附注:
使用clang编译native code,使用O3或者Oz选项基本上能一步到位,不能不说clang太牛X了,和gcc根本不在一个量级!
转自:http://www.cnblogs.com/octave/p/4454205.html
感谢作者
- Android NDK 如何缩减库的大小
- Android NDK 如何缩减库的大小
- 如何缩减word文档大小
- Android ndk之so体积缩减
- 缩减APK包大小的方法
- Android NDK 缩小编译库的体积大小
- android studio 清除无用资源,缩减apk大小!
- 缩减网络模型大小
- 如何缩减VMware虚拟机的磁盘空间
- 使用DBCC缩减数据库中log文件的大小
- Android NDK下面如何使用zlib的库
- Android NDK 如何使用自己的共享库
- Android NDK 如何使用自己的共享库
- Android NDK 如何使用自己的共享库
- Android NDK下面如何使用zlib的库
- linux下,使用lvm 创建、扩充 、缩减 逻辑磁盘大小,以及相应的文件系统大小
- lvm 创建、扩充 、缩减 逻辑磁盘大小,以及相应的文件系统大小
- [译]Google新logo是如何缩减13000字节的
- [经典排序算法][集锦]
- 解决常见的masksToBounds离屏渲染带来的性能损耗
- 阿里数据研发工程师实习生面试经历
- 用VLC搭建流媒体服务器
- jquery mobile实例
- Android NDK 如何缩减库的大小
- Android微信支付遇到的坑
- Android中ListView的addFooterView不显示的问题
- 字符串连接:使用StringBuffer#append来替代”+”真的会带来性能提升吗?
- Swift 正向传值以及利用闭包(closure)实现反向传值(七)
- CentOS7 安装 mongodb3.2.3 详细步骤
- 用vlc搭建简单的流媒体代理服务器
- iOS 离屏渲染的研究
- Java 回顾笔记_Sting类1