需要从C ++项目调用Java项目。所以我写了包装器。不幸的是我的主要语言是Java,而且我在C或C ++中没有做任何事情。似乎我在代码中的某处发生了内存泄漏,但我不知道在哪里。
这是包装器的代码:
#include <cstdint>
#include <jni.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <memory>
#include "wrapperJava.h"
#include <stdint.h>
using namespace std;
JNIEnv* env;
jmethodID javaMethodCreate;
jclass javaClass;
int init = 0;
jint rate = 16000;
jint channels = 1;
jint bits = 16;
JNIEnv* create_vm()
{
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[2];
args.version = JNI_VERSION_1_8;
args.nOptions = 2;
options[0].optionString = "-Djava.class.path=./router-core-0.0.1-SNAPSHOT.jar:./cp:cp/antlr-2.7.7.jar:cp/aopalliance-1.0.jar:cp/asm-3.3.1.jar:cp/aspectjweaver-1.8.9.jar:cp/bcprov-jdk15on-1.51.jar:cp/cdi-api-1.1.jar:cp/classmate-1.3.3.jar:cp/commons-codec-1.10.jar:cp/commons-io-2.5.jar:cp/commons-lang3-3.4.jar:cp/commons-logging-1.1.1.jar:cp/cryptacular-1.0.jar:cp/cxf-core-3.0.12.jar:cp/cxf-rt-bindings-soap-3.0.12.jar:cp/cxf-rt-bindings-xml-3.0.12.jar:cp/cxf-rt-databinding-jaxb-3.0.12.jar:cp/cxf-rt-frontend-simple-3.0.12.jar:cp/cxf-rt-ws-addr-3.0.12.jar:cp/cxf-rt-ws-policy-3.0.12.jar:cp/cxf-rt-wsdl-3.0.12.jar:cp/dom4j-1.6.1.jar:cp/ehcache-2.10.3.jar:cp/el-api-2.2.jar:cp/geronimo-javamail_1.4_spec-1.7.1.jar:cp/guava-16.0.1.jar:cp/h2-1.0.60.jar:cp/hibernate-commons-annotations-5.0.1.Final.jar:cp/hibernate-core-5.2.2.Final.jar:cp/hibernate-entitymanager-5.2.2.Final.jar:cp/hibernate-jpa-2.1-api-1.0.0.Final.jar:cp/hibernate-validator-5.2.4.Final.jar:cp/hsqldb-2.3.3.jar:cp/httpclient-4.5.3.jar:cp/httpcore-4.4.5.jar:cp/httpmime-4.5.3.jar:cp/jackson-annotations-2.8.5.jar:cp/jackson-core-2.8.5.jar:cp/jackson-databind-2.8.5.jar:cp/jain-sip-ri-1.2.324.jar:cp/jandex-2.0.0.Final.jar:cp/jasypt-1.9.2.jar:cp/java-support-7.1.1.jar:cp/javassist-3.20.0-GA.jar:cp/javax.inject-1.jar:cp/javax.transaction-api-1.2.jar:cp/jaxb-core-2.2.11.jar:cp/jaxb-impl-2.2.11.jar:cp/jboss-interceptors-api_1.1_spec-1.0.0.Beta1.jar:cp/jboss-logging-3.3.0.Final.jar:cp/jcl-over-slf4j-1.7.25.jar:cp/jnotify-0.94.jar:cp/joda-time-2.9.6.jar:cp/jsr250-api-1.0.jar:cp/jul-to-slf4j-1.7.25.jar:cp/log4j-over-slf4j-1.7.25.jar:cp/logback-classic-1.1.8.jar:cp/logback-core-1.1.8.jar:cp/lombok-1.16.6.jar:cp/neethi-3.0.3.jar:cp/opensaml-2.5.1-1.jar:cp/opensaml-core-3.1.1.jar:cp/opensaml-profile-api-3.1.1.jar:cp/opensaml-saml-api-3.1.1.jar:cp/opensaml-saml-impl-3.1.1.jar:cp/opensaml-security-api-3.1.1.jar:cp/opensaml-security-impl-3.1.1.jar:cp/opensaml-soap-api-3.1.1.jar:cp/opensaml-xacml-api-3.1.1.jar:cp/opensaml-xacml-impl-3.1.1.jar:cp/opensaml-xacml-saml-api-3.1.1.jar:cp/opensaml-xacml-saml-impl-3.1.1.jar:cp/opensaml-xmlsec-api-3.1.1.jar:cp/opensaml-xmlsec-impl-3.1.1.jar:cp/openws-1.4.2-1.jar:cp/postgresql-9.4.1212.jre7.jar:cp/router-schema-0.0.1-SNAPSHOT.jar:cp/router-sip-0.0.1-SNAPSHOT.jar:cp/slf4j-api-1.7.25.jar:cp/snakeyaml-1.17.jar:cp/spring-aop-4.3.5.RELEASE.jar:cp/spring-aspects-4.3.5.RELEASE.jar:cp/spring-beans-4.3.5.RELEASE.jar:cp/spring-boot-1.4.3.RELEASE.jar:cp/spring-boot-autoconfigure-1.4.3.RELEASE.jar:cp/spring-boot-starter-1.4.3.RELEASE.jar:cp/spring-boot-starter-aop-1.4.3.RELEASE.jar:cp/spring-boot-starter-data-jpa-1.4.3.RELEASE.jar:cp/spring-boot-starter-jdbc-1.4.3.RELEASE.jar:cp/spring-boot-starter-logging-1.4.3.RELEASE.jar:cp/spring-boot-starter-security-1.4.3.RELEASE.jar:cp/spring-boot-starter-tomcat-1.4.3.RELEASE.jar:cp/spring-boot-starter-web-1.4.3.RELEASE.jar:cp/spring-context-4.3.5.RELEASE.jar:cp/spring-core-4.3.5.RELEASE.jar:cp/spring-data-commons-1.12.6.RELEASE.jar:cp/spring-data-jpa-1.10.6.RELEASE.jar:cp/spring-expression-4.3.5.RELEASE.jar:cp/spring-jdbc-4.3.5.RELEASE.jar:cp/spring-orm-4.3.5.RELEASE.jar:cp/spring-oxm-4.3.5.RELEASE.jar:cp/spring-security-config-4.1.4.RELEASE.jar:cp/spring-security-core-4.1.4.RELEASE.jar:cp/spring-security-web-4.1.4.RELEASE.jar:cp/spring-tx-4.3.5.RELEASE.jar:cp/spring-web-4.3.5.RELEASE.jar:cp/spring-webmvc-4.3.5.RELEASE.jar:cp/spring-ws-core-2.3.1.RELEASE.jar:cp/spring-ws-security-2.3.1.RELEASE.jar:cp/spring-xml-2.3.1.RELEASE.jar:cp/stax2-api-3.1.4.jar:cp/tomcat-embed-core-8.5.6.jar:cp/tomcat-embed-el-8.5.6.jar:cp/tomcat-embed-websocket-8.5.6.jar:cp/tomcat-jdbc-8.5.6.jar:cp/tomcat-juli-8.5.6.jar:cp/validation-api-1.1.0.Final.jar:cp/woodstox-core-asl-4.4.1.jar:cp/wsdl4j-1.6.3.jar:cp/wss4j-1.6.19.jar:cp/wss4j-ws-security-common-2.1.4.jar:cp/wss4j-ws-security-dom-2.1.4.jar:cp/xml-resolver-1.2.jar:cp/xmlschema-core-2.2.1.jar:cp/xmlsec-1.5.8.jar:cp/xmltooling-1.3.2-1.jar";
options[1].optionString = "-Xmx12000m";
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
JNI_CreateJavaVM(&jvm, (void **)&env, &args);
return env;
}
void invoke_main()
{
jmethodID mainMethod;
jclass javaClass;
jobjectArray applicationArgs;
javaClass = env->FindClass("org/springframework/boot/loader/JarLauncher");
mainMethod = env->GetStaticMethodID(javaClass, "main", "([Ljava/lang/String;)V");
applicationArgs = env->NewObjectArray(0, env->FindClass("java/lang/String"), NULL);
env->CallStaticVoidMethod(javaClass, mainMethod, applicationArgs);
}
void init_jni_methods()
{
javaClass = env->FindClass("com/some/direct/DirectEndpoint");
javaMethodCreate = env->GetStaticMethodID(javaClass, "createModel", "([BIII)[B");
}
int invoke_create_model(std::shared_ptr<uint8_t> data, int length, std::vector<uint8_t> &templ)
{
jbyteArray baArg = env->NewByteArray(length);
env->SetByteArrayRegion(baArg, 0, length, data.get());
jbyteArray jValue = NULL;
jValue = (jbyteArray)env->CallStaticObjectMethod(javaClass, javaMethodCreate, baArg, rate, channels, bits);
env->DeleteLocalRef(baArg);
if (env->ExceptionOccurred()) // check if an exception occurred
{
if(jValue != NULL)
{
env->DeleteLocalRef(jValue);
}
return -1;
}
uint8_t* value = NULL;
int len = 0;
if(jValue != NULL)
{
len = env->GetArrayLength(jValue);
value = env->GetByteArrayElements(jValue, JNI_FALSE);
templ.assign(value, value + len);
env->ReleaseByteArrayElements(jValue, value, JNI_ABORT);
env->DeleteLocalRef(jValue);
return 0;
}
else
{
printf("No enough data for creation");
return -1;
}
}
ReturnStatus createModel(const Record &record, std::vector<uint8_t> &templ)
{
ReturnStatus ret = ReturnStatus(ReturnCode::Success, std::string("OK"));
try
{
int i = invoke_create_model(record.data, record.length, templ);
if( i != 0 )
{
ret = ReturnStatus(ReturnCode::CreationError, "Error during creation: no enough data");
}
}
catch(...)
{
ret = ReturnStatus(ReturnCode::CreationError, "Error during creation: no enough data");
}
return ret;
}
ReturnStatus initialize(const std::string &configDir)
{
if( init ==0 )
{
env = create_vm();
invoke_main();
init_jni_methods();
init = 1;
}
return ReturnStatus(ReturnCode::Success, "OK");
}
首先调用initialize然后调用createModel。这两个调用都来自外部项目,其中记录和templ参数ara管理。
Java中没有内存泄漏,因为Java代码在生产中有数千个调用。使用此包装器的项目在使用:
调用createModel的一千零半迭代后崩溃terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
The program has unexpectedly finished.
/home/test/app crashed.
我已经看到了很多类似的问题,并在这个包装中检查了eveything,但它没有产生任何效果。
我忘了释放一些记忆吗?
我是否理解在Java代码中创建的所有内容以及未返回到C ++包装器的内容是否由Java GC管理?
UPD: 解决了。 问题是“templ”向量的数据存储在外部项目的RAM中。而外部项目的堆只限于1.3-2Gb。因此,经过大约1400次迭代后,每次出现此错误时都会推出1Mb数据。