JVM总内存通常为64 MB,但有时仅为2 MB

时间:2019-11-29 13:36:53

标签: java java-native-interface

我创建了一个包含从C#代码调用的JNI函数的DLL。这个功能由长期运行的GUI应用程序C#应用程序多次调用。

我的JNI函数调用JNI_GetCreatedJavaVMs。如果虚拟机为零,则通过函数JNI_CreateJavaVM()创建一个,否则我的函数调用AttachCurrentThread()

然后我的函数调用FindClass()并从JAR文件中加载类。

最后,我在该类上调用一个方法。

在被调用方法的Java代码中,我首先调用方法totalMemory()并将结果写入日志文件。然后该方法执行其他一些操作。

通常,方法totalMemory()返回的值约为6600万,即大约64 MB,但有时返回的值约为200万,即2 MB。当totalMemory()只有2 MB时,我的java方法会抛出OutOfMemoryError(java堆空间),因为没有足够的内存来分配我的java方法需要做的对象。

请注意,我的java方法包含catch (Throwable),以便C#应用程序可以继续。在OutOfMemoryError之后,对于以后对我的JNI函数的调用,totalMemory()将再次返回64 MB的值。

什么会导致分配给JVM的总内存从64 MB减少到2 MB?

请注意,我指的是总内存,而不是空闲内存。我认为总内存不应更改。我相信我的日志文件证明了我的假设,因为如上所述,它几乎总是64 MB。有时只是下降到2 MB,因此出现了这个问题。为什么总内存有时会下降到2 MB?

我的(精简的)JNI代码。

#include <jni.h>

void main()
{
    JavaVM *jvm;
    JNIEnv *env;
    JavaVMInitArgs vm_args;
    jint rslt;
    jclass cls;
    jmethodID mid;
    jobject jObj;

    JavaVMOption* options = new JavaVMOption[1];
    options[0].optionString = "-Djava.class.path=jni_test.jar";

    vm_args.version = JNI_VERSION_1_10;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;

    rslt = JNI_CreateJavaVM(&jvm, (void**) &env, &vm_args);
    cls = env->FindClass("jni_test/JniTest0");
    mid = env->GetStaticMethodID(cls, "getReply", "()Ljava/lang/String;");
    jObj = env->CallStaticObjectMethod(cls, mid);
}

在上面的JNI代码中调用的我的(简化的)java方法。

public static String getReply() {
    long totalMemory = Runtime.getRuntime().totalMemory();
    System.out.println("total memory = " + totalMemory);
    String reply = "That is the correct answer! Well done!";
    return reply;
}

2 个答案:

答案 0 :(得分:1)

据我了解的JVM内存模型:

maxMemory是JVM可以使用的最大数量(由-Xmx定义)

maxMemory = totalMemory +未分配的内存

totalMemory-freeMemory = used

尽管很少(afaik)看到JVM将内存释放回操作系统, 可能并且会解释您的经历。

totalMemory不应低于-Xms定义的值, 因此以固定的内存值运行jvm可能会解决您的问题。 例如:-Xms64m -Xmx64m

答案 1 :(得分:0)

我的怀疑似乎已被证明是正确的。有时错误消息可能会引起误解。从一开始我就感到直觉不是问题,实际上不是内存问题,就像我说的那样,看来我是对的。

我的代码使用Java日志记录将日志文件写入Windows临时文件夹中。事实证明,另一个不相关的进程也将日志文件写入同一文件夹。实际上,它实际上将数千个文件写入该文件夹,并且这些文件永远不会删除。删除这些文件后,问题就消失了。

所以问题出在以下事实:临时文件夹已满,文件爆满-我的代码都不写。可以检查是否有人遇到类似问题并由于互联网搜索而出现在这里。