android开发中,有时候需要控制包的大小,这样就会要求对代码进行优化,

下面这个文章不错。大家可参考

原文链接 https://blog.algolia.com/android-ndk-how-to-reduce-libs-size/

when we started Algolia Development for Android, binary size optimization was not one of our main concerns. In fact we even started to develop in JAVA before switching to C/C++ for reasons of performance.

We were reminded of the importance of binary size by  who informed us that it would be difficult to integrate our lib in  Android Application because its size. AVelov is 638KB and Algolia was 850KB, which would mean that AVelov would more than double in size with Algolia Search embedded.

To address this problem we managed to reduce Algolia binary size from 850KB to 307KB. In this post we share how we did it.

Do not use Exceptions and RTTI

We actually do not use exceptions in our native lib, but for the sake of completeness, I’ll cover this point too.

C++ exceptions and RTTI are disabled by default but you can enable them viaAPP_CPPFLAGS in your Application.mk file and use a compatible STL, for example:

APP_CPPFLAGS += -fexceptions -frtti

APP_STL := stlport_shared

Whilst using exceptions and RTTI can help you to use existing code, it will obviously increase your binary size. If you have a way to remove them, go for it! Actually, there’s another reason to avoid using C++ exceptions: their support is still far from perfect. For example if was impossible for us to catch a C++ exception and launch a Java exception in JNI. The following code results in a crash (will probably be fixed in a future release of the Android NDK toolchain):

try {

...

} catch (std::exception& e) {

env->ThrowNew(env->FindClass("java/lang/Exception"), "Error occured");

}

Do not use iostream

When starting to investigate our library size following Cyril’s feedback, we discovered that Algolia binaries had vastly increased in size since our last release (from 850KB to 1.35MB)! We first suspected the Android NDK toolchain since we upgraded it and tested different toolchains, but we only observed minor changes.

By dichotomy search in our commits, we discovered that a single line of code was responsible for the inflation:

std::cerr << .... << std::endl;

As incredible as it may sound, using iostream increases a lot the binary size. Our tests shown that it adds a least 300KB per architecture! You must be very careful with iostream and prefer to use __android_log_print method:

#include #define APPNAME "MyApp"

__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "The value of 1 + 1 is %d", 1+1);

Make sure you also link against the logging library, in your Android.mk file:

LOCAL_LDLIBS := -llog

Use -fvisibility=hidden

An efficient way to reduce binary size is to use the  of gcc. This feature lets you control which functions will be exported in the symbols table. Hopefully, JNI comes with a JNIEXPORT macro that flags JNI functions as public. You just have to check that all functions used by JNI are prefixed by JNIEXPORT, like this one:

JNIEXPORT void JNICALL Java_ClassName_MethodName

(JNIEnv *env, jobject obj, jstring javaString)

Then you have just to add -fvisibility=hidden for C and C++ files in Android.mk file:

LOCAL_CPPFLAGS += -fvisibility=hidden

LOCAL_CFLAGS += -fvisibility=hidden

In our case the binaries were down to 809KB (-5%) but remember the gains may be very different for your project. Make your own measures!

Discard Unused Functions with gc-sections

Another interesting approach is to remove unused code in the binary. It can drastically reduce its size if for example part of your code is only used for tests.

To enable this feature, you just have to change the C and C++ compilation flags and the linker flags in Android.mk:

LOCAL_CPPFLAGS += -ffunction-sections -fdata-sections

LOCAL_CFLAGS += -ffunction-sections -fdata-sections

LOCAL_LDFLAGS += -Wl,--gc-sections

Of course you can combine this feature with the visibility one:

LOCAL_CPPFLAGS += -ffunction-sections -fdata-sections -fvisibility=hidden

LOCAL_CPPFLAGS += -ffunction-sections -fdata-sections -fvisibility=hidden

LOCAL_CFLAGS += -ffunction-sections -fdata-sections  LOCAL_LDFLAGS += -Wl,--gc-sections

This optim only got us a 1% gain, but once combined with the previous visibility one, we were down to 691KB (-18.7%).

Remove Duplicated Code

You can remove duplicated code with the –icf=safe option of the linker. Be careful, this option will probably remove your code inlining, you must check that this flag does not impact performance.

This option is not yet available on the mips architecture so you need to add an architecture check in Android.mk:

ifneq ($(TARGET_ARCH),mips)

LOCAL_LDFLAGS += -Wl,--icf=safe

endif

And if you want to combine this option with gc-sections:

ifeq ($(TARGET_ARCH),mips)

LOCAL_LDFLAGS += -Wl,--gc-sections

else

LOCAL_LDFLAGS += -Wl,--gc-sections,--icf=safe

endif

We actually only obtained a 0.8% gain in size with this one. All previous optimizations combined, we were now at 687KB (-19.2%).

Change the Default Flags of the Toolchain

If you want to go even further, you can change the default compilation flags of the toolchain. Flags are not identical accross architectures, for example:

inline-limit is set to 64 for arm and set to 300 for x86 and mips

Optimization flag is set to -Os (optimize for size) for arm and set to -O2 (optimize for performance) for x86 and mips

As arm is used by the large majority of devices, we have applied arm settings for other architectures. Here is the patch we applied on the 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)

We were good for a 8.5% gain with these new flags. Once combined with previous optimizations, we were now at 613KB (-27.9%).

Limit the Number of Architectures

Our final suggestion is to limit the number of architectures. Supporting armeabi-v7a is mandory for performance if you have a lot of floating point computation, but armeabi will provide a similar result if you do not need a FPU. As for mips processors… well they just are not in use on the market today.

And if binary size is really important to you, you can just limit your support to armeabi and x86 architectures in Application.mk:

APP_ABI := armeabi x86

Obviously, this optim was the killer one. Dropping two out of four architectures halved the binaries size. Overall we obtained a size of 307KB, a 64% gain from the initial 850KB (not counting the bump at 1.35MB due to iostream).

Conclusion

I hope this post will help you to reduce the size of your native libraries on Android since default flags are far from optimal. Don’t expect to obtain the same size reductions, they will highly depend on your specific usage. And if you know other methods to reduce binary size, please share in the comments!

android.mk 优化编译,android下ndk编译c优化相关推荐

  1. android.mk 比较字变量,Android.mk的用法和基础

    一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...

  2. android mk与bp,Android.bp你真的了解吗

    Android.bp你真的了解吗 前言 最近在捣鼓Android 9 和10的build系统,看到一篇比较好的博客,大名鼎鼎的gityuan的,奉上链接理解Android.bp,为了方便学习和更多的人 ...

  3. android.mk 执行脚本,Android.mk的用法

    (1)Android.mk是什么? Android.mk是Android提供的一种makefile文件.Android.mk其实是把真正的Makefile包装起来,做成了一个对使用者来说很简单的东西. ...

  4. 构建Android的交叉编译器、用NDK编译移植

    在之前的文章中提到了用arm-none-linux-gnueabi-gcc交叉编译移植程序到Android平台上.也提到了,Android中没有glibc,所以arm-none-linux-gnuea ...

  5. android zbar编译,zbar android sdk在CentOS 7下的编译和使用

    环境:CentOS 7+NDK 20.0.5594570+libiconv-1.14 下载 编译libiconv-1.14 1.执行./configure 2.执行make 报错,提示 error: ...

  6. android.mk编译动态库,安卓之Android.mk多文件以及动态库编译

    1.多文件编译 多文件编译共有两种方式: (1) 在Android.mk中一一添加 LOCAL_PATH:= $(call my-dir) #定义当前模块的相对路径 include $(CLEAR_V ...

  7. linux下ndk编译命令行程序及配置

    1.在http://developer.android.com/tools/sdk/ndk/index.html下载Android-ndk-r8e-linux-x86.tar.bz2,解压后 把and ...

  8. android.mk遍历子目录,android 保存文件的各种目录列表

    一般的,我们可以通过context和Environment来获取要保存文件的目录 ($rootDir) +- /data -> Environment.getDataDirectory() | ...

  9. android mk subst功能,Android.mk(零)

    Android.mk可以生产的基本文件 LOCAL_PATH:P=$(call my-dir)   //返回该Android.mk所在目录的路径,必须放在第一行 定义了当前模块的相对路径 includ ...

最新文章

  1. oracle里的ols机制,Oracle ASM的AU(Allocation units)分配
  2. bigdecimal 等于0_好程序员Java培训分享BigDecimal的用法
  3. 重谈ExtGrid 扩展行自动展开(一)(expanded row 默认展开)
  4. 漏洞learning[安全大事记]
  5. 在IDEA中设置Java的堆大小
  6. Keil综合(01)一些常见文件类型的作用和功能说明
  7. imregionalmax
  8. 如何使用qtp检查网页中显示的文字颜色为指定的颜色
  9. ASA virtual telnet
  10. 乔布斯声称Google先决定当苹果的敌人
  11. 三菱PLC定位控制2
  12. 使用VS Code插件Code Runner一键运行ANSYS命令流
  13. 2010年计算语言学分词作业——采用二元语法模型与viterbi算法分词
  14. 使用 Notepad 或 TextEdit 来编写 HTML
  15. HTML:利用canvas画定位图标
  16. java获取京东token_京东宙斯平台使用方法(accesstoken,appkey,appsecret参数和SDK的获取)...
  17. 编程修养 - 来自网络整理
  18. 【C++面向对象程序设计——侯捷大师】心得摘要
  19. 小米电视4a刷鸿蒙,小米电视4A精简系统教程
  20. Linux为什么无法进入文件,Linux系统运维之CentOS下提示“无法打开并写入文件”问题解决...

热门文章

  1. 集合-1(Collection、迭代器、Collections、泛型)
  2. stm32之USB应用实例(官方例程资料下载使用)
  3. mysql 视图慢_第03问:磁盘 IO 报警,MySQL 读写哪个文件慢了?
  4. 乐鑫代理启明云端分享|基于ESP32-S2彩色触摸屏86面板方案
  5. 语言怎么把横的光标变成竖的_想练字,先会学会控笔吧!基础都不牢,怎么练招式?...
  6. java treemap 内存_Java中Map、HashMap、LinkedHashMap、TreeMap的区别
  7. 英伟达账号登录邮箱验证收不到_【硬核教学】解决登录230锁定
  8. Leetcode300. Longest Increasing Subsequence最长上升子序列
  9. CocosCreator内置函数实现物体拖动
  10. Android中应用安装分析