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

JVM Total Memory Usually 64 MB But Sometimes Only 2 MB

我创建了一个 DLL,其中包含一个从 C# 代码调用的 JNI 函数。该函数被 C# 应用程序多次调用,该应用程序是一个长 运行 GUI 应用程序。

我的 JNI 函数调用 JNI_GetCreatedJavaVMs. If there are zero VMs, then one is created via function JNI_CreateJavaVM(), otherwise my function calls AttachCurrentThread()

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

最后我在 class 上调用了一个方法。

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

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

请注意,我的 java 方法包含 catch (Throwable),以便 C# 应用程序可以继续。在 OutOfMemoryError 之后,对于我的 JNI 函数的后续调用,totalMemory() 将再次 return 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;
}

据我了解JVM内存模型:

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

maxMemory = totalMemory + 未分配内存

totalMemory - freeMemory = used

虽然很少(afaik)看到 JVM 将内存释放回 OS, 它可能会解释你正在经历的事情。

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

我的怀疑似乎被证明是正确的。有时错误消息可能会产生误导。从一开始我就有直觉,这个问题并不是真正的内存问题,就像我说的,看来我是对的。

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

所以问题在于临时文件夹中充满了文件 - none 其中的文件是我的代码编写的。要检查是否有人遇到过类似的问题,并且由于互联网搜索而出现在这里。