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

如何通过JNI/C++零拷贝填充Java管理的Apache Arrow向量

Apache Arrow JNI/C++ 直接填充Java侧预分配向量实践

1. Java端分配向量并传递至C++

复用你现有导出流程,但调整为传递未完成填充的向量:

  • 用RootAllocator创建向量,调用vector.allocateNew(int capacity)预留足够容量(必须明确指定容量,确保内存已分配)
  • 不要调用setValueCount,直接分配ArrowSchema和ArrowArray
  • 调用Data.exportVector(vector, allocator, arrowArray, arrowSchema)导出向量元数据
  • 通过JNI将arrowArray和arrowSchema的指针传递给C++

注意:此时Java侧向量处于已分配内存但未设置有效长度的状态,C++端将直接写入这片预分配的内存。

2. C++端获取原始指针直接写入内存

导入数组后,强制转换为对应类型的Arrow数组,即可通过raw_values()获取连续内存指针,彻底解决Value(index)的性能问题:

// 从JNI获取ArrowArray和ArrowSchema指针
arrow::Result<std::shared_ptr<arrow::Array>> import_result = arrow::ImportArray(*jni_arrow_array, *jni_arrow_schema);
std::shared_ptr<arrow::Array> imported_array = import_result.ValueOrDie();

// 转换为具体类型(以Int32Array为例)
auto int32_array = std::static_pointer_cast<arrow::Int32Array>(imported_array);

// 获取可写的原始数据指针(直接指向Java预分配的内存)
int32_t* writable_data_ptr = const_cast<int32_t*>(int32_array->raw_values());

// 示例:批量写入数据
const int batch_size = 1000000;
for (int i = 0; i < batch_size; ++i) {
    writable_data_ptr[i] = i * 2;
}

3. C++端完成向量收尾(设置长度等)

直接修改导入数组的有效长度,并同步到JNI传递的ArrowArray结构体,确保Java端能感知到数据变化:

// 设置实际填充的元素数量
int actual_length = 1000000;
imported_array->SetValueCount(actual_length);

// 同步修改ArrowArray结构体的length字段
jni_arrow_array->length = actual_length;

若向量支持空值,还需处理有效性位图:通过int32_array->mutable_validity()获取可写的bitmap指针,用arrow::bitmap::SetBit/ClearBit设置对应位置的空值状态。

4. Java端低开销读取向量

C++端完成写入并同步长度后,Java侧无需额外拷贝,直接使用原向量即可:

  • 调用vector.getValueCount()会自动读取C++设置的有效长度
  • 直接通过vector.get(index)或批量访问方法读取数据,内存无需二次拷贝
  • 使用完毕后正常调用vector.close()释放内存

内容的提问来源于stack exchange,提问作者Timothy Miller

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 06:45:30