openharmony 鸿蒙 use-jsvm-about-external-arraybuffer

2026-08-25 浏览 (1)

使用JSVM-API接口从外部内存创建ArrayBuffer

简介

ArrayBuffer是JavaScript中的一种数据类型,用于表示通用的、固定长度的原始二进制数据缓冲区。它提供了一种在JavaScript中有效地表示和操作原始二进制数据的方式。

在某些场景下,应用已有一块外部内存(如从文件映射、硬件缓冲区、或其他Native模块分配的内存),希望将其包装为JavaScript的ArrayBuffer对象,以便在JS层进行读写操作。从API Version 26.0.0开始,JSVM-API提供了OH_JSVM_CreateArrayBufferFromExternalMemory接口来满足这类场景。

基本概念

  • 零拷贝与拷贝:该接口不保证零拷贝。在某些JSVM实现或版本中,外部内存可能被拷贝到引擎内部缓冲区。输出参数copied显示当前是否发生了拷贝。开发者不应依赖零拷贝行为,因为copied的值可能随JSVM版本演进而发生变化。
  • 内存生命周期:该接口接收可选的类型为JSVM_FinalizeArrayBuffer的回调函数,回调函数中包含bool copied参数,指示数据是否被拷贝。当copied为false(零拷贝)时,ArrayBuffer直接引用外部内存,调用方必须保证在finalizeCb被调用之前不释放该内存(调用方可在回调函数中释放外部内存);当copied为true时,调用方可在API返回后立即释放外部内存。

接口说明

注意

此接口是实验性接口,需定义JSVM_EXPERIMENTAL宏后方可使用。

接口功能说明
OH_JSVM_CreateArrayBufferFromExternalMemory从外部内存创建ArrayBuffer对象。

参数说明

参数项描述
JSVM_Env env调用JSVM-API的环境。
void *externalData外部内存指针。必须8字节对齐
size_t byteLength外部内存的长度(字节)。不得超过引擎最大ArrayBuffer大小。
JSVM_FinalizeArrayBuffer finalizeCb可选参数。当ArrayBuffer被GC回收时调用的callback。回调签名含bool copied参数,指示是否发生了拷贝。byteLength==0时此参数应该传递NULL。
void* finalizeHint可选参数。传递给finalizeCb的自定义提示数据。
bool* copied可选输出参数。为true表示数据被拷贝,为false表示零拷贝
JSVM_Value *result输出参数。创建的ArrayBuffer对象。

JSVM_FinalizeArrayBuffer回调类型

typedef void (*JSVM_FinalizeArrayBuffer)(JSVM_Env env, void* finalizeData, void* finalizeHint, bool copied);
参数说明
env环境句柄。始终为NULL,不可使用。
finalizeData调用API时传入的externalData指针。
finalizeHint调用API时传入的finalizeHint指针。
copied是否发生了拷贝。true表示引擎拷贝了数据,原始externalData内存不受引擎管理;false表示零拷贝,引擎直接引用了externalData内存。

JSVM_FinalizeArrayBuffer回调函数将会在关联的ArrayBuffer对象被回收时被调用,用以执行native的清理动作。使用JSVM_FinalizeArrayBuffer请遵循以下规则:

  • 由于JSVM_FinalizeArrayBuffer回调函数的调用时机具有不确定性(可能是GC期间,也可能是虚拟机销毁期间等),回调时JSVM环境可能已经销毁,因此JSVM_FinalizeArrayBufferenv参数始终是NULL。

  • 回调函数仅做资源释放,不要执行复杂逻辑。回调函数中不能调用其他JSVM API。

  • 回调函数可能在非JSVM主线程上调用,如果回调需要访问共享状态,必须使用原子操作或锁进行同步。

  • 根据copied参数决定内存的释放策略。

返回值

  • JSVM_OK:创建成功。
  • JSVM_INVALID_ARG:参数非法,可能原因:result为NULL;byteLength>0但externalData为NULL;externalData未8字节对齐;byteLength超过引擎最大限制;byteLength==0但finalizeCb不为NULL。

注意事项

  1. 需开启实验性宏:在#include "ark_runtime/jsvm.h"#include "ark_runtime/jsvm_types.h"前必须#define JSVM_EXPERIMENTAL,否则接口不可见。
  2. 不保证零拷贝copied输出参数的值取决于当前JSVM实现,可能随版本演进而变化。开发者不应在业务逻辑中依赖零拷贝行为,否则会产生未定义行为。
  3. 8字节对齐:externalData必须8字节对齐,否则返回JSVM_INVALID_ARG。
  4. 利用copied参数管理内存
    • 推荐方式:在finalizeCb中根据copied参数决定是否释放外部内存。当copied为false时应该在finalizeCb中释放外部内存(否则会造成ArrayBuffer底层内存泄漏)。
    • finalizeCbcopied参数与API输出参数copied的值始终一致。
  5. finalizeCb调用时机:finalizeCb在ArrayBuffer对象被GC回收时调用,调用时机不确定。不要在finalizeCb中执行耗时操作。

使用示例

JSVM-API接口开发流程参考使用JSVM-API实现JS与C/C++语言交互开发流程,本文仅对接口对应C++相关代码进行展示。

本示例介绍了如何从外部内存创建ArrayBuffer,并根据copied参数合理管理外部内存生命周期。

cpp部分代码:

#define JSVM_EXPERIMENTAL  // 必须在include jsvm.h之前定义,否则无法调用实验接口
#include "napi/native_api.h"
#include "ark_runtime/jsvm.h"
#include "hilog/log.h"
#include <cstdlib>
#include <cstring>
// ...

// 模拟从外部模块获取图像像素数据(RGBA,4像素)
static void *LoadPixelData(size_t *outSize)
{
    *outSize = 16;  // 4pixels×4bytes(RGBA)
    uint8_t *data = static_cast<uint8_t *>(malloc(*outSize));
    if (data == nullptr) {
        return nullptr;
    }
    // 填充示例像素:红、绿、蓝、白
    uint8_t pixels[] = {
        255, 0, 0, 255,     // 红
        0, 255, 0, 255,     // 绿
        0, 0, 255, 255,     // 蓝
        255, 255, 255, 255  // 白
    };
    memcpy(data, pixels, *outSize);
    return data;
}

// finalize回调:利用copied参数判断是否需要释放外部内存
static void PixelDataFinalize(JSVM_Env env, void *data, void *hint, bool copied)
{
    if (!copied) {
        // 零拷贝模式:引擎释放了对外部内存的引用,开发者负责释放
        free(data);
    } else {
        // 拷贝模式:引擎已拷贝数据,原始内存应已在API返回后被释放
        // data指针可能已失效,不要使用
    }
}

// OH_JSVM_CreateArrayBufferFromExternalMemory的样例方法
static JSVM_Value CreateArrayBufferFromExternal(JSVM_Env env, JSVM_CallbackInfo info)
{
    JSVM_Value undef = nullptr;
    OH_JSVM_GetUndefined(env, &undef);
    // 1. 从外部模块获取数据(malloc分配,满足8字节对齐要求)
    size_t dataSize = 0;
    void *pixelData = LoadPixelData(&dataSize);
    if (pixelData == nullptr) {
        OH_LOG_ERROR(LOG_APP, "JSVM: failed to load pixel data");
        return undef;
    }

    JSVM_HandleScope scope = nullptr;
    OH_JSVM_OpenHandleScope(env, &scope);

    // 2. 创建ArrayBuffer
    JSVM_Value arrayBuffer = nullptr;
    bool copied = false;
    JSVM_Status status = OH_JSVM_CreateArrayBufferFromExternalMemory(
        env, pixelData, dataSize, PixelDataFinalize, nullptr, &copied, &arrayBuffer);
    if (status != JSVM_OK) {
        OH_LOG_ERROR(LOG_APP, "JSVM CreateArrayBufferFromExternalMemory: failed");
        free(pixelData);  // 创建失败时需手动释放
        return undef;
    }

    // 3. 根据copied参数管理原始内存
    if (copied) {
        // 引擎拷贝了数据,原始外部内存不再被引擎使用,可立即释放
        free(pixelData);
    }
    // copied==false时:引擎直接使用了外部内存,finalizeCb会在GC时负责释放

    // 4. 通过OH_JSVM_GetArraybufferInfo获取ArrayBuffer的数据指针来访问数据。
    //    不要直接使用pixelData指针,因为在拷贝模式下ArrayBuffer内部使用的
    //    是拷贝后的数据,pixelData指向的是原始外部内存。
    void *abData = nullptr;
    size_t abLen = 0;
    OH_JSVM_GetArraybufferInfo(env, arrayBuffer, &abData, &abLen);
    OH_LOG_INFO(LOG_APP, "JSVM CreateArrayBufferFromExternalMemory: success, "
                "byteLength=%{public}zu", abLen);

    OH_JSVM_CloseHandleScope(env, scope);

    // 触发GC回收External ArrayBuffer
    OH_JSVM_MemoryPressureNotification(env, JSVM_MEMORY_PRESSURE_LEVEL_CRITICAL);
    return undef;
}

// CreateArrayBufferFromExternal注册回调
static JSVM_CallbackStruct param[] = {
    {.data = nullptr, .callback = CreateArrayBufferFromExternal},
};
static JSVM_CallbackStruct *method = param;
// CreateArrayBufferFromExternal方法别名,供JS调用
static JSVM_PropertyDescriptor descriptor[] = {
    {"createArrayBufferFromExternal", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
};
// 样例测试js
const char *SRC_CALL_NATIVE = R"JS(
createArrayBufferFromExternal();
)JS";

预期结果:

JSVM CreateArrayBufferFromExternalMemory: success, byteLength=16

你可能感兴趣的鸿蒙文章

openharmony 鸿蒙 use-napi-ark-runtime

openharmony 鸿蒙 use-napi-about-arraybuffer

openharmony 鸿蒙 use-jsvm-about-array

openharmony 鸿蒙 use-napi-load-module

openharmony 鸿蒙 jsvm-data-types-interfaces

openharmony 鸿蒙 ohos-abi

openharmony 鸿蒙 jsvm-guidelines

openharmony 鸿蒙 use-jsvm-trigger-gc

openharmony 鸿蒙 use-sendable-napi

openharmony 鸿蒙 use-napi-object-wrap

  • 所属分类: 后端技术
  • 本文标签: 鸿蒙 软件
  • 版权声明: 本文链接 https://seaxiang.com/blog/joUXE6iP