Android JNI优化

使用共享C++ 运行时库

在NDK中使用 C++ 时,请使用最新 NDK,并选择使用 libc++ 共享STL 做为 C++ STL,这样可使多个 so 共享一个 C++ STL,由于使用静态STL将会在每一个 so 库中出现重复代码,增长应用大小,而且因为全局数据和静态构造函数在内的 STL 将同时存在于两个库中。此应用的运行时行为未定义,所以在实际运行过程当中,应用会常常崩溃。例如:内存在一个库中分配,而在另外一个库中释放,从而致使内存泄漏或堆损坏。java

解决方案

  • ndk-build

在 Application.mk 中添加android

APP_STL := c++_shared
复制代码
  • cmake

在 build.gradle 中添加ios

externalNativeBuild {
    cmake {
        arguments "-DANDROID_STL=c++_shared"
  }
}
复制代码

libc++_shared.so 冲突解决

使用 c++_shared 编译后 aar 中将附带 libc++_shared.so,若是有多个aar 都附带了 libc++_shared.so,将致使APP工程中编译不过,此时能够采起下面两种办法:c++

  • APP 工程中 build.gradle 中添加编译配置
packagingOptions {
    pickFirst 'lib/*/libc++_shared.so'
}
复制代码
  • 在编译 so 库的工程 build.gradle 中添加配置排除 libc++_shared.so, 由App工程负责添加 libc++_shared.so :
libraryVariants.all { variant ->
    def bundleTask = variant.packageLibrary
    def reBundleTask = tasks.create("reBundle${variant.name.capitalize()}Aar", Zip) {
        def dir = bundleTask.destinationDir
        def path = bundleTask.archivePath
        def name = bundleTask.archiveName
        archiveName name + ".bak"
        destinationDir dir
        from(zipTree(path)) {
            exclude "jni/*/libc++_shared.so"
        }
        doLast {
            delete path
            file("$dir/$name" + ".bak").renameTo(path)
        }
    }
    bundleTask.finalizedBy reBundleTask
    variant.assemble.dependsOn reBundleTask
}
复制代码

开启编译优化

若是使用 GCC 能够 -Os 打开优化,若是使用 Clang 能够 -Oz 打开优化小程序

解决方案

  • ndk-build

在 Android.mk 中添加api

LOCAL_CFLAGS += -Os -Oz
LOCAL_CPPFLAGS += -Os -Oz
复制代码
  • cmake

在 build.gradle 中添加bash

externalNativeBuild {
    cmake {
        cFlags "-Os -Oz"
        cppFlags "-Os -Oz"
    }
}
复制代码

隐藏符号

-fvisibility=hidden
复制代码

隐藏elf符号表,能够减小 so 文件大小,提高性能 注意:须要在提供给 java 层暴露的JNI函数能够 在方法上添加 JNIEXPORT 宏或者添加属性 attribute ((visibility ("default")))函数

-fvisibility-inlines-hidden
复制代码

隐藏全部内联函数,从而减少导出符号表的大小,既能缩减文件的大小,还能提升运行性能性能

解决方案

  • ndk-build

在 Android.mk 中添加gradle

LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_CPPFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden
复制代码
  • cmake 在 build.gradle 中添加
externalNativeBuild {
    cmake {
        cFlags "-fvisibility=hidden"
 		cppFlags "-fvisibility=hidden -fvisibility-inlines-hidden"
 	}
}
复制代码

删除无用函数

使用 --gc-section 编译选项减少程序体积

解决方案

  • ndk-build

在 Android.mk 中添加

LOCAL_CPPFLAGS += -ffunction-sections -fdata-sections
LOCAL_CFLAGS += -ffunction-sections -fdata-sections 
LOCAL_LDFLAGS += -Wl,--gc-sections
复制代码
  • cmake

在 build.gradle 中添加

externalNativeBuild {
    cmake {
        cFlags "-ffunction-sections -fdata-sections"
        cppFlags "-ffunction-sections -fdata-sections"
    }
}
复制代码

不使用异常和RTTI

在C++ 中使用异常和 RTTI 会显著增长文件大小,所以尽可能不要在 C++中 使用异常和 RTTI,若是代码中没有使用到 异常和 RTTI 请删除相关 feature 和 flags

解决方案

  • ndk-build
从 LOCAL_CPP_FEATURES 中 删除 exceptions 和 rtti
从 APP_CPPFLAGS 中 删除 -frtti 和 -fexceptions
从 LOCAL_CPPFLAGS 中 删除 -frtti 和 -fexceptions
复制代码
  • cmake
删除 cppFlags "-frtti"
删除 cppFlags "-fexceptions"
复制代码

不使用iostream

尽可能不要在 C++ 代码中使用 iostream,如:

#include<iostream>
std::cout << "test" <<std::endl;
复制代码

其余相似用法:std::cin,std::cout,std::cerr,std::clog,std::wcin,std::wcout,std::wcerr,std::wclog

这样没有什么做用而且会显著增长 so 文件大小

解决方案

删除 iostream 相关代码调用,若是有打日志须要可使用 __android_log_print

#define LOG_TAG "native_log"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
复制代码
相关文章
相关标签/搜索