TypedArrays —在V8和Java之间共享内存
前言:本文章只是个人翻译自用,不喜欢者勿喷
最近在研究android与js交互
奈何本人能力有限,又是英语渣渣,特用机译方便理解
J2V8提供了将V8和Node.js与JVM 链接的技术。使用JNI,Java开发人员可以直接调用V8和Node.js API。这种无缝集成为Java生态系统带来了改进的JavaScript性能,NPM模块和Node.js API。一种替代方法是调用两个单独的进程(Java和Node.js),并在它们之间使用服务协议。但是,单进程方法的优点之一是能够在JavaScript和Java之间共享内存。在本文中,我们将探讨如何使用TypedArrays在V8和JVM之间提供共享内存空间。
类型化数组是类似数组的对象,并提供了一种用于访问原始二进制数据的机制。TypedArrays规范同时描述了后备存储(ArrayBuffer)和该存储的视图(例如,Int32Array)。ArrayBuffer设计用于内存中大数据块的组装,这些数据可以直接映射到连续的内存区域,例如GPU上的内存。在J2V8 4中,ArrayBuffers直接映射到Java ByteBuffer(java.nio.ByteBuffer)。这意味着当字节以JavaScript写入TypedArrays时,它们立即在Java中可用,反之亦然。J2V8确保数组缓冲区的ByteOrder与您的系统体系结构匹配。
Handle arrayBuffer = Local::New(isolate, *reinterpret_cast<Persistent*>(objectHandle));
void* dataPtr = arrayBuffer->GetContents().Data();
jobject byteBuffer = env->NewDirectByteBuffer(dataPtr, capacity);
return byteBuffer;
V8ArrayBuffer 包含一个名为getBackingStore()的方法,该方法 提供对java.nio.ByteBuffer的直接访问。
例如,如果您有一个包含大型二进制数据(例如图像)的类型化数组,这将非常有用。可以使用Java或JavaScript处理这种类型的数组,而无需跨JNI桥复制数据。这产生了一个非常强大的编程模型,您可以在其中切换JavaScript(Node.js)和Java。
在此示例中,我们使用Jimp在JavaScript中加载图片。
var Jimp = require('/Users/irbull/node_modules/jimp');
Jimp.read('/Users/irbull/Downloads/IMG_20160706_175824.jpg', (err, image) => {
if (err) throw err;
process_in_java(image.bitmap.data);
image.write('/Users/irbull/Downloads/output.jpg');
});
但是,我们将使用Java处理每个字节,而不是使用JavaScript处理图像。在这个简单的例子中,我们将使用简单平均算法创建灰度图像 。
V8TypedArray typedArray = (V8TypedArray) parameters.get(0);
ByteBuffer buffer = typedArray.getByteBuffer();
try {
for(int i = 0; i < buffer.limit(); i+=4) {
int red = 0xFF & buffer.get(i);
int green = 0xFF & buffer.get(i+1);
int blue = 0xFF & buffer.get(i+2);
int gray = (int) (red + green + blue ) / 3;
buffer.put(i, (byte) gray);
buffer.put(i+1, (byte) gray);
buffer.put(i+2, (byte) gray);
};
} finally {
typedArray.release();
}
return null;
}
由于Java和JavaScript都在同一个字节数组上运行,因此不会执行昂贵的数据复制。此外,我们只需调用image.write保存图像。这可以用Java或JavaScript来调用。该示例的完整代码可在GitHub上找到。
package com.eclipsesource.j2v8.tutorial;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import com.eclipsesource.v8.NodeJS;
import com.eclipsesource.v8.Releasable;
import com.eclipsesource.v8.V8Array;
import com.eclipsesource.v8.V8Object;
import com.eclipsesource.v8.V8TypedArray;
public class Exercise1 {
private static String JIMP_SCRIPT = "var Jimp = require('/Users/irbull/node_modules/jimp');\n"
+ " Jimp.read('/Users/irbull/Downloads/IMG_20160706_175824.jpg', (err, image) => {\n"
+ " if (err) throw err;\n"
+ " process_in_java(image.bitmap.data);\n"
+ " image.write('/Users/irbull/Downloads/output.jpg');\n"
+ " });\n";
public static void main(String[] args) throws IOException {
final NodeJS nodeJS = NodeJS.createNodeJS();
nodeJS.getRuntime().registerJavaMethod((V8Object receiver, V8Array parameters) -> {
V8TypedArray typedArray = (V8TypedArray) parameters.get(0);
ByteBuffer buffer = typedArray.getByteBuffer();
try {
for(int i = 0; i < buffer.limit(); i+=4) {
int gray = createGrayscale(buffer, i);
buffer.put(i, (byte) gray);
buffer.put(i+1, (byte) gray);
buffer.put(i+2, (byte) gray);
};
} finally {
typedArray.release();
}
return null;
}, "process_in_java");
File script = createTemporaryScriptFile(JIMP_SCRIPT, "jimpscript.js");
nodeJS.exec(script);
while(nodeJS.isRunning()) {
nodeJS.handleMessage();
}
nodeJS.release();
}
private static int createGrayscale(ByteBuffer buffer, int i) {
int red = 0xFF & buffer.get(i);
int green = 0xFF & buffer.get(i+1);
int blue = 0xFF & buffer.get(i+2);
int gray = (int) (red + green + blue ) / 3;
return gray;
}
public static void executeJSFunction(V8Object object, String name) {
Object result = object.executeFunction(name, null);
if (result instanceof Releasable) {
((Releasable) result).release();
}
}
public static void executeJSFunction(V8Object object, String name, Object... params) {
Object result = object.executeJSFunction(name, params);
if (result instanceof Releasable) {
((Releasable) result).release();
}
}
private static File createTemporaryScriptFile(final String script, final String name) throws IOException {
File tempFile = File.createTempFile(name, ".js");
PrintWriter writer = new PrintWriter(tempFile, "UTF-8");
try {
writer.print(script);
} finally {
writer.close();
}
return tempFile;
}
}
TypedArrays也可以用Java创建并直接传递给JavaScript。
V8ArrayBuffer buffer = new V8ArrayBuffer(v8, 100);
new V8TypedArray(v8, buffer, V8Value.INT_16_ARRAY, 0, 50);
V8TypedArrays采用ArrayBuffer,视图类型,偏移量和长度。视图类型指定如何解释字节。在这种情况下,所有值都应解释为带符号的16位整数。这类似于在JavaScript中指定 TypedArrays的方式。