├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── cpp │ ├── CMakeLists.txt │ └── mem_test.cpp │ ├── java │ └── me │ │ └── zhilong │ │ └── tools │ │ └── abortkiller │ │ └── demo │ │ └── MainActivity.kt │ └── res │ ├── drawable │ └── ic_launcher.png │ ├── layout │ └── activity_main.xml │ └── values │ ├── colors.xml │ └── themes.xml ├── build.gradle ├── demo └── patrons-demo-1.1.0.apk ├── gradle.properties ├── gradle ├── publish.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── patrons ├── .gitignore ├── build.gradle ├── gradle.properties ├── lib-proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── cpp │ ├── CMakeLists.txt │ ├── patrons_core.c │ ├── patrons_core.h │ └── xhook │ │ ├── queue.h │ │ ├── tree.h │ │ ├── xh_core.c │ │ ├── xh_core.h │ │ ├── xh_elf.c │ │ ├── xh_elf.h │ │ ├── xh_errno.h │ │ ├── xh_log.c │ │ ├── xh_log.h │ │ ├── xh_util.c │ │ ├── xh_util.h │ │ ├── xh_version.c │ │ ├── xh_version.h │ │ ├── xhook.c │ │ └── xhook.h │ └── java │ └── com │ └── alibaba │ └── android │ └── patronus │ ├── Patrons.java │ └── _Patrons.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | .idea -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Alibaba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | Source code Licensed under the BSD 2-Clause License 24 | =================================================== 25 | 26 | tree.h 27 | 28 | Copyright 2002 Niels Provos 29 | All rights reserved. 30 | 31 | Redistribution and use in source and binary forms, with or without 32 | modification, are permitted provided that the following conditions 33 | are met: 34 | 1. Redistributions of source code must retain the above copyright 35 | notice, this list of conditions and the following disclaimer. 36 | 2. Redistributions in binary form must reproduce the above copyright 37 | notice, this list of conditions and the following disclaimer in the 38 | documentation and/or other materials provided with the distribution. 39 | 40 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 41 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 42 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 43 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 44 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 46 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 47 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 48 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 49 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | 51 | 52 | Source code Licensed under the BSD 3-Clause License 53 | =================================================== 54 | 55 | queue.h 56 | 57 | Copyright (c) 1991, 1993 The Regents of the University of California. 58 | All rights reserved. 59 | 60 | Redistribution and use in source and binary forms, with or without 61 | modification, are permitted provided that the following conditions 62 | are met: 63 | 1. Redistributions of source code must retain the above copyright 64 | notice, this list of conditions and the following disclaimer. 65 | 2. Redistributions in binary form must reproduce the above copyright 66 | notice, this list of conditions and the following disclaimer in the 67 | documentation and/or other materials provided with the distribution. 68 | 3. Neither the name of the University nor the names of its contributors 69 | may be used to endorse or promote products derived from this software 70 | without specific prior written permission. 71 | 72 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 73 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 74 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 75 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 76 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 77 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 78 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 79 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 80 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 81 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 82 | SUCH DAMAGE. 83 | 84 | Source code Licensed under the MIT License 85 | ========================================== 86 | 87 | xhook/xh_* xhook/xhook.c xhook/xhook.h 88 | 89 | Permission is hereby granted, free of charge, to any person obtaining a copy 90 | of this software and associated documentation files (the "Software"), to deal 91 | in the Software without restriction, including without limitation the rights 92 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 93 | copies of the Software, and to permit persons to whom the Software is 94 | furnished to do so, subject to the following conditions: 95 | 96 | The above copyright notice and this permission notice shall be included in all 97 | copies or substantial portions of the Software. 98 | 99 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 100 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 101 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 102 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 103 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 104 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 105 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Patrons 2 | 3 | [![Download](https://maven-badges.herokuapp.com/maven-central/com.alibaba/patrons/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.alibaba/patrons) 4 | 5 | `🎉 A framework for improving android 32bit app stability. (Alleviate crashes caused by insufficient virtual memory)` 6 | 7 | 一行代码解决 Android 32位应用因虚拟内存不足导致的 libc:abort(signal 6) 8 | 9 | ## 一、背景 10 | 目前国内的 Android App 大多数还是32位架构,仅提供了 arm-v7a 的动态链接库,市面上大多数手机都是64位的 CPU,App 通常都运行在兼容模式下,可以使用完整的 4GB 虚拟内存,但是国内应用一般都是集万千功能于一身,随着业务越来越复杂(内置webview、小程序、高清大图、短视频等等),以及部分内存泄漏,4GB 的内存越来越不够用了。 11 | 12 | 从去年(2020)开始,各大头部应用的 Native Crash 开始暴增,通常 Top1 都是 `libc:abort`,通过上报的 maps 可见,虚拟内存地址空间大部分接近了 4GB,console logs 中也有大量的 `GL Errors: Out of memory(12)`。 13 | 14 | 针对此问题,一般首先能想到的就是排查内存泄漏问题,但往往收效甚微,多半是因为随着业务的发展,确实是需要这么多虚拟内存。诚然通过升级64位架构可以把地址空间上限扩充到512GB,但是因为各种原因(包大小、维护成本等等),目前大部分应用尚未完成升级,所以在这里提供一种新的思路。 15 | 16 | (还是推荐大家尽快把自己的应用升级到64位架构哦~ 至少是双ABI架构,32位版本中可以继续保留 Patrons 用于提升存量用户的体验。) 17 | 18 | ## 二、原理 19 | 通过一系列技术手段实现运行期间动态调整`Region Space`预分配的地址空间,释放出最多`900MB`(根据实际情况调整参数)虚拟内存给到 libc:malloc,增加了接近30%的地址上限,大幅度给应用续命。 20 | 21 | 详细介绍:[阿里开源 Patrons:大型 32 位 Android 应用稳定性提升 50% 的“黑科技”](https://www.infoq.cn/article/bvbf3iwjztvem4szamvw) 22 | 23 | ## 三、使用方式 24 | 编译`patrons`模块 or 使用以下中心仓库的坐标,主工程依赖该模块产物,在合适的时机进行初始化: 25 | 26 | ```groovy 27 | repositories { 28 | mavenCentral() 29 | } 30 | dependencies { 31 | implementation 'com.alibaba:patrons:1.1.0' 32 | } 33 | ``` 34 | 35 | ```java 36 | com.alibaba.android.patronus.Patrons.init(context, null); 37 | ``` 38 | 39 | ##### [→ 测试 Demo 下载](https://github.com/alibaba/Patrons/blob/develop/demo/patrons-demo-1.1.0.apk) 40 | 41 | ## 四、Q & A 42 | 43 | 1. SDK 本身会带来多少接入成本(包大小、稳定性):包大小增加20k左右,可以忽略不计;关键逻辑中会有多层保护,不会引发新的崩溃。 44 | 45 | 2. SDK 兼容性怎么样:在 Android 8、8.1、9、10、11、12 共 6 个主流版本生效,覆盖率接近 99.9%。在未兼容机型中不会生效,亦不会产生新的崩溃。 46 | 47 | 3. 使用后就能根治 Abort 么:肯定不能,因为 Abort 的成因很多,虽然32位应用多半是因为虚拟内存不足,但是也可能存在其他问题,适配性还是要具体情况具体分析。 -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | } 5 | 6 | android { 7 | compileSdkVersion rootProject.ext.compileSdkVersion 8 | buildToolsVersion rootProject.ext.buildToolsVersion 9 | ndkVersion rootProject.ext.ndkVersion 10 | 11 | defaultConfig { 12 | applicationId "me.zhilong.tools.abortkiller.demo" 13 | minSdkVersion 16 14 | targetSdkVersion rootProject.ext.targetSdkVersion 15 | versionCode 1 16 | versionName rootProject.ext.versionName 17 | 18 | externalNativeBuild { 19 | cmake { 20 | abiFilters rootProject.ext.abiFilters.split(",") 21 | arguments "-DANDROID_STL=c++_shared" 22 | } 23 | } 24 | } 25 | 26 | buildTypes { 27 | debug { 28 | ndk { 29 | abiFilters "armeabi-v7a" 30 | } 31 | } 32 | release { 33 | minifyEnabled true 34 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 35 | 36 | ndk { 37 | abiFilters "armeabi-v7a" 38 | } 39 | } 40 | } 41 | externalNativeBuild { 42 | cmake { 43 | path "src/main/cpp/CMakeLists.txt" 44 | version rootProject.ext.cmakeVersion 45 | } 46 | } 47 | compileOptions { 48 | sourceCompatibility JavaVersion.VERSION_1_8 49 | targetCompatibility JavaVersion.VERSION_1_8 50 | } 51 | kotlinOptions { 52 | jvmTarget = '1.8' 53 | } 54 | } 55 | 56 | dependencies { 57 | implementation project(path: ':patrons') 58 | 59 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 60 | implementation 'androidx.core:core-ktx:1.2.0' 61 | implementation 'androidx.appcompat:appcompat:1.2.0' 62 | implementation 'com.google.android.material:material:1.3.0' 63 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 64 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | -optimizationpasses 1 24 | -optimizations code/removal/simple,code/removal/advanced,code/removal/variable,code/removal/exception,code/simplification/branch,code/simplification/field,code/simplification/cast,code/simplification/arithmetic,code/simplification/variable 25 | #-optimizations code/removal/simple,code/removal/advanced,method/removal/parameter,method/inlining/short,method/inlining/tailrecursion 26 | # ignoring warnings, that gets the scala app to work, but is a bit dangerous... 27 | -ignorewarnings 28 | -target 1.8 29 | # -dontobfuscate 30 | 31 | -keep public class * extends android.app.Activity 32 | -keep public class * extends android.app.Application 33 | -keep public class * extends android.app.Service 34 | -keep public class * extends android.content.BroadcastReceiver 35 | -keep public class * extends android.content.ContentProvider 36 | -keep public class * extends android.app.backup.BackupAgentHelper 37 | -keep public class * extends android.preference.Preference 38 | 39 | -keepclassmembernames class me.zhilong.tools.abortkiller.demo.MainActivity { 40 | private *; 41 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10.2) 2 | 3 | project("memory-alloc") 4 | 5 | find_library(log-lib log) 6 | 7 | add_library(memory-alloc SHARED 8 | mem_test.cpp 9 | ) 10 | 11 | target_link_libraries( 12 | memory-alloc 13 | ${log-lib} 14 | ) -------------------------------------------------------------------------------- /app/src/main/cpp/mem_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zhilong.lzl on 3/17/21. 3 | // 4 | 5 | #include 6 | #include 7 | #include "string" 8 | #include 9 | #include "vector" 10 | 11 | using namespace std; 12 | 13 | static constexpr size_t KB = 1024; 14 | static constexpr size_t MB = KB * KB; 15 | 16 | void *tryMalloc(size_t size) { 17 | void *stub = malloc(size * MB); 18 | 19 | if (stub == nullptr) { 20 | return tryMalloc(size / 2); 21 | } else { 22 | __android_log_print(ANDROID_LOG_INFO, "patrons", "malloc success, stub = %p, size = %d", 23 | stub, size); 24 | 25 | return stub; 26 | } 27 | } 28 | 29 | extern "C" JNIEXPORT void JNICALL 30 | Java_me_zhilong_tools_abortkiller_demo_MainActivity_native_1alloc(JNIEnv *env, jobject thiz) { 31 | tryMalloc(100); 32 | } 33 | 34 | extern "C" JNIEXPORT void JNICALL 35 | Java_me_zhilong_tools_abortkiller_demo_MainActivity_abort(JNIEnv *env, jobject thiz) { 36 | // abort(); 37 | char *p = NULL; 38 | *p = '1'; 39 | } -------------------------------------------------------------------------------- /app/src/main/java/me/zhilong/tools/abortkiller/demo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package me.zhilong.tools.abortkiller.demo 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.util.Log 6 | import android.view.View 7 | import android.widget.Button 8 | import androidx.appcompat.app.AppCompatActivity 9 | import com.alibaba.android.patronus.Patrons 10 | import com.alibaba.android.patronus.Patrons.PatronsConfig 11 | import kotlin.system.measureTimeMillis 12 | 13 | class MainActivity : AppCompatActivity() { 14 | val MB = 1024 * 1024 15 | 16 | val manyString = ArrayList() 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(R.layout.activity_main) 21 | 22 | findViewById