当前位置: 首页 > 工具软件 > J2V8 > 使用案例 >

学习j2v8--TypedArrays —在V8和Java之间共享内存

燕刚捷
2023-12-01

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的方式。

 类似资料: