You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native请求大体积Get API时内存不足的解决方案咨询

问题描述

调用返回60-80MB大小Base64格式PDF/图片的GET接口时,React Native应用崩溃并弹出“Out of Memory”错误,但该接口在Postman和Web应用中可正常响应。相关环境配置及代码如下:

依赖版本

"@react-navigation/drawer": "^5.8.0",
    "@react-navigation/native": "^5.4.2",
    "@react-navigation/stack": "^5.3.9",
    "react": "16.11.0",
    "react-native": "0.62.2",
    "react-native-blob-util": "^0.13.18",

app/build.gradle文件

apply plugin: "com.android.application"
apply plugin: 'com.google.gms.google-services'

import com.android.build.OutputFile

project.ext.react = [
    enableHermes: false,  // clean and rebuild if changing
]

apply from: "../../node_modules/react-native/react.gradle"


def enableSeparateBuildPerCPUArchitecture = false


def enableProguardInReleaseBuilds = true


def jscFlavor = 'org.webkit:android-jsc:+'

def enableHermes = project.ext.react.get("enableHermes", false);

android {
    compileSdkVersion rootProject.ext.compileSdkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
   

    defaultConfig {
        applicationId "com.enterprisesales.uat"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.2"
        multiDexEnabled true
    }
    splits {
        abi {
            reset()
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false  // If true, also generate a universal APK
            include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
        }
    }
    signingConfigs {
        release {
            if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
                storeFile file(MYAPP_RELEASE_STORE_FILE)
                storePassword MYAPP_RELEASE_STORE_PASSWORD
                keyAlias MYAPP_RELEASE_KEY_ALIAS
                keyPassword MYAPP_RELEASE_KEY_PASSWORD
            }
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            // Caution! In production, you need to generate your own keystore file.
            // see https://facebook.github.io/react-native/docs/signed-apk-android.
            signingConfig signingConfigs.release
            minifyEnabled enableProguardInReleaseBuilds
            shrinkResources enableProguardInReleaseBuilds
            zipAlignEnabled enableProguardInReleaseBuilds
            useProguard enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }

    packagingOptions {
        pickFirst "lib/armeabi-v7a/libc++_shared.so"
        pickFirst "lib/arm64-v8a/libc++_shared.so"
        pickFirst "lib/x86/libc++_shared.so"
        pickFirst "lib/x86_64/libc++_shared.so"
        pickFirst 'lib/x86_64/libjsc.so'
        pickFirst 'lib/arm64-v8a/libjsc.so'
    }

    dexOptions {
        javaMaxHeapSize "4g"
    }

    // applicationVariants are e.g. debug, release
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // For each separate APK per architecture, set a unique version code as described here:
            // https://developer.android.com/studio/build/configure-apk-splits.html
            def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
            def abi = output.getFilter(OutputFile.ABI)
            if (abi != null) {  // null for the universal-debug, universal-release variants
                output.versionCodeOverride =
                        versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
            }

        }
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    //noinspection GradleDynamicVersion
    implementation "com.facebook.react:react-native:+"  // From node_modules

    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
    implementation 'com.android.support:multidex:1.0.3'
     

    // Add the dependencies for any other desired Firebase products
    // https://firebase.google.com/docs/android/setup#available-libraries
         
 

    debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
      exclude group:'com.facebook.fbjni'
    }

    debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
        exclude group:'com.facebook.flipper'
    }

    debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
        exclude group:'com.facebook.flipper'
    }

    if (enableHermes) {
        def hermesPath = "../../node_modules/hermes-engine/android/";
        debugImplementation files(hermesPath + "hermes-debug.aar")
        releaseImplementation files(hermesPath + "hermes-release.aar")
    } else {
        implementation jscFlavor
    }
    compile project(':react-native-exit-app')
}

// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
    from configurations.compile
    into 'libs'
}

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

AndroidManifest.xml文件

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.package.uat">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:name=".MainApplication"
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:largeHeap="true"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:theme="@style/AppTheme"
        android:usesCleartextTraffic="true">

        <activity
            android:name=".MainActivity"
            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="adjustPan">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
                <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
            </intent-filter>
        </activity>

        <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />

    </application>

</manifest>

API调用函数(Get请求)

const url = `${Config.ApiEndPoints.API_GET_DOCUMENT}`
const header = { "Authorization": `Bearer ${Config.UserSession.USER_DATA.token}` }
const apiResponse = await Module.ApiModule.GetRequest(url, header)
const baseResponse = await fetch(url, {
        method: TYPE === undefined ? "GET" : TYPE,
        headers: {
            "Content-Type": "application/json",
            ...header
        },
    }).then(r => r.json()).catch(error => {
        Module.DropDownAlert.showAlert("error", Config.String.SOME_ERROR_OCCURS, Config.String.SOMETHING_WENT_WRONG)
        return null
    })

解决方案

1. 绕开JS层处理大Base64数据

当前用fetch直接获取并解析JSON的方式会把整个大Base64字符串加载到JS内存中,这是内存溢出的核心原因。改用已安装的react-native-blob-util直接在原生层处理文件流,跳过JS层的内存占用:

import RNBlobUtil from 'react-native-blob-util';

const downloadLargeFile = async () => {
  const url = `${Config.ApiEndPoints.API_GET_DOCUMENT}`;
  const header = { "Authorization": `Bearer ${Config.UserSession.USER_DATA.token}` };
  
  try {
    // 保存到本地文档目录
    const savePath = RNBlobUtil.fs.dirs.DocumentDir + '/target_file.pdf';
    await RNBlobUtil.config({
      path: savePath,
      fileCache: true
    })
    .fetch('GET', url, header);
    
    // 后续直接用本地路径操作文件(比如预览、上传等)
    console.log('文件已保存至:', savePath);
  } catch (error) {
    Module.DropDownAlert.showAlert("error", Config.String.SOME_ERROR_OCCURS, Config.String.SOMETHING_WENT_WRONG);
  }
};

2. 优化Android内存配置

  • 启用Hermes引擎:将app/build.gradle中的enableHermes改为true,Hermes相比默认JSC引擎内存占用更低,修改后需clean项目并重新编译:
    project.ext.react = [
        enableHermes: true,
    ]
    
  • 精简ABI架构:在defaultConfig中添加ndk配置,只保留常用架构,减少包体积和内存开销:
    defaultConfig {
        // ...其他配置
        ndk {
            abiFilters "armeabi-v7a", "arm64-v8a"
        }
    }
    

3. 清理冗余代码与内存

  • 删除重复接口调用:你的代码中同时调用了Module.ApiModule.GetRequest和fetch,这会重复加载数据,直接移除其中一个冗余调用。
  • 主动释放内存:处理完数据后,将不再使用的变量设为null,触发JS垃圾回收:
    let baseResponse = await fetch(...);
    // 处理完数据后
    baseResponse = null;
    

4. 调整ProGuard配置

确保ProGuard没有误删内存优化相关代码,在proguard-rules.pro中添加:

-keep class com.facebook.react.bridge.** { *; }
-keep class com.facebook.hermes.** { *; }

内容的提问来源于stack exchange,提问作者Vishwajeet Gade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 16:48:20