JNI嵌入R至Java时遇C栈溢出及JIT初始化失败求助
问题:嵌入R到Java(JNI)时出现C栈溢出及JIT初始化失败错误
此前已解决编译R的libR库并通过JNI在Java中加载的问题,目前能成功加载libR,但运行时出现以下R错误:
##Trying load RSession ##LOADED !! RSession RSession.c:Java_RSession_test:15 RSession.c:Java_RSession_initEmbeddedR:21 [0] /path/to/TMP/R-4.3.2/bin/R [1] --vanilla [2] --quiet [3] --encoding=UTF-8 [4] --no-init-file [5] --no-readline RSession.c:Java_RSession_initEmbeddedR:35 Error: C stack usage 134897775332 is too close to the limit Error: C stack usage 134897775380 is too close to the limit Error: C stack usage 134897775268 is too close to the limit Fatal error: unable to initialize the JIT
怀疑是R层面的递归问题,但无法定位原因,且HOME目录中无.Renviron、.Rprofile等配置文件。以下是可复现问题的最小代码:
Java代码
public class RSession { // 声明本地方法 public static native int initEmbeddedR(int argc, String[] argv); public static native void endEmbeddedR(int fatal); public static native void test(); public static void main(String[] args) throws Throwable { final String R_HOME = System.getenv("R_HOME"); if(R_HOME==null || R_HOME.isEmpty()) { System.err.println("undefined R_HOME"); System.exit(-1); } final String libName= "RSession"; System.err.println("##Trying load "+libName); try { System.loadLibrary(libName); } catch(Throwable err) { System.err.println("##Cannot load "+libName); err.printStackTrace(); System.exit(-1); } System.err.println("##LOADED !! "+libName); test(); String[] argv = {args[0],"--vanilla","--quiet","--encoding=UTF-8","--no-init-file","--no-readline"}; int result = RSession.initEmbeddedR(argv.length, argv); System.out.println("initEmbeddedR returned result: " + result); RSession.endEmbeddedR(0); System.out.println("endEmbeddedR called successfully"); } }
C代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <Rinternals.h> #include <Rembedded.h> #include <R_ext/Parse.h> #include <jni.h> #include "RSession.h" #define WHERE fprintf(stderr,"%s:%s:%d\n",__FILE__,__FUNCTION__,__LINE__) JNIEXPORT void JNICALL Java_RSession_test (JNIEnv * env, jclass clazz) { WHERE; } JNIEXPORT jint JNICALL Java_RSession_initEmbeddedR(JNIEnv *env, jobject obj, jint argc, jobjectArray argv) { WHERE; int i; int len = (*env)->GetArrayLength(env, argv); char **args = (char **)malloc(len * sizeof(char *)); for (i = 0; i < len; i++) { jstring string = (jstring)(*env)->GetObjectArrayElement(env, argv, i); const char *rawString = (*env)->GetStringUTFChars(env, string, 0); args[i] = strdup(rawString); fprintf(stderr,"[%d] %s\n",i,args[i]); (*env)->ReleaseStringUTFChars(env, string, rawString); } WHERE; int result = Rf_initEmbeddedR(argc, args); WHERE; // 释放为C字符串分配的内存 for (i = 0; i < len; i++) { free(args[i]); } free(args); WHERE; return result; } JNIEXPORT void JNICALL Java_RSession_endEmbeddedR(JNIEnv *env, jobject obj, jint fatal) { // 调用C函数 WHERE; Rf_endEmbeddedR(fatal); WHERE; }
Makefile
SHELL=/bin/bash CC=gcc R_VERSION=4.3.2 test: TMP/RSession.class TMP/libRSession.so echo | R_HOME=${PWD}/TMP/lib/R PATH=$${PATH}:{PWD}/TMP/R-$(R_VERSION)/bin java -Djava.library.path=${PWD}/TMP:TMP/R-$(R_VERSION)/lib -cp TMP RSession "${PWD}/TMP/R-$(R_VERSION)/bin/R" TMP/libRSession.so : RSession.c TMP/R-$(R_VERSION)/lib/libR.so TMP/RSession.h $(CC) -ITMP -I$${JAVA_HOME}/include/ -I$${JAVA_HOME}/include/linux \ -LTMP/R-$(R_VERSION)/lib `TMP/R-$(R_VERSION)/bin/R CMD config --cppflags` -shared -fPIC -o $@ -g $< -lR TMP/RSession.h : TMP/RSession.class touch -c $@ TMP/RSession.class : RSession.java mkdir -p TMP javac -h TMP -d TMP $< touch $@ TMP/R-$(R_VERSION)/lib/libR.so : rm -rvf "TMP/R-$(R_VERSION)" TMP/jeter.tar.gz mkdir -p $(dir $@) wget -O TMP/jeter.tar.gz "https://pbil.univ-lyon1.fr/CRAN/src/base/R-4/R-$(R_VERSION).tar.gz" (cd TMP && tar xfz jeter.tar.gz && rm jeter.tar.gz && cd R-$(R_VERSION) && ./configure --with-pcre1 --enable-R-shlib --with-x=no --prefix=${PWD}/TMP && make && make install)
内容的提问来源于stack exchange,提问作者Pierre
相关产品推荐
相关产品推荐

