Tengo una devolución de llamada JNI:JNI se acopla/desacopla la gestión de memoria hilo
void callback(Data *data, char *callbackName){
JNIEnv *env;
jvm->AttachCurrentThread((void **)&env, NULL);
/* start useful code*/
/* end useful code */
jvm->DetachCurrentThread();
}
Cuando lo ejecuto como esto (código útil vacío), consigo una pérdida de memoria. Si comento el método completo, no hay filtración. ¿Cuál es la forma correcta de unir/separar hilos?
Mi aplicación procesa datos de sonido en tiempo real, por lo que los hilos responsables del procesamiento de datos deben hacerse lo más pronto posible para estar listos para otro lote. Entonces, para estas devoluciones de llamada, creo nuevos hilos. Hay docenas o incluso cientos de ellos por segundo, se conectan a JVM, llaman a una función de devolución de llamada que vuelve a dibujar un gráfico, se desprende y muere. ¿Es esta una forma correcta de hacer esto? ¿Cómo manejar la memoria que gotea?
EDIT: errata
Aceptar He creado un código mimimal necesario:
package test;
public class Start
{
public static void main(String[] args) throws InterruptedException{
System.loadLibrary("Debug/JNITest");
start();
}
public static native void start();
}
y
#include <jni.h>
#include <Windows.h>
#include "test_Start.h"
JavaVM *jvm;
DWORD WINAPI attach(__in LPVOID lpParameter);
JNIEXPORT void JNICALL Java_test_Start_start(JNIEnv *env, jclass){
env->GetJavaVM(&jvm);
while(true){
CreateThread(NULL, 0, &(attach), NULL, 0, NULL);
Sleep(10);
}
}
DWORD WINAPI attach(__in LPVOID lpParameter){
JNIEnv *env;
jvm->AttachCurrentThread((void **)&env, NULL);
jvm->DetachCurrentThread();
return 0;
}
y cuando corro el perfilador VisualJM, consigo el patrón de diente de sierra de costumbre, no hay fugas allí. El uso del montón alcanzó un máximo de 5 MB. Sin embargo, observar el explorador de procesos de hecho muestra un comportamiento extraño: la memoria sube y baja lentamente, 4K por segundo durante un minuto y luego, de repente, toda la memoria asignada disminuye. Estas gotas no se corresponden con la recolección de basura (se producen con menos frecuencia y desasignan menos memoria que los dientes de sierra en el perfilador).
Así que mi mejor opción es que se trata de un comportamiento del sistema operativo que maneja decenas de miles de hilos de milisegundos de vida. ¿Algún gurú tiene una explicación para esto?
Veo su punto de vista y normalmente estoy de acuerdo. Los hilos que estoy creando son muy efímeros. Los creo (usando WinApi CreateThread), luego los adjunto inmediatamente a la JVM.En Java, repintan un gráfico Swing con un nuevo valor. Cuando terminen, se separarán y cesarán la ejecución (return 0), en cuyo punto deberían ser destruidos por el sistema operativo. Se usan para pasar un nuevo valor a Java. Hay aproximadamente 40 de ellos por segundo para cada canal de sonido (trabajo con hasta 32 canales). –
Puede considerar la agrupación de subprocesos. Haga que sus subprocesos permanezcan por más tiempo y tome entrada de una cola, en lugar de generar continuamente nuevos subprocesos. Esto reducirá la sobrecarga de gestión de subprocesos tanto en el sistema operativo como en Java. – technomage
Si está haciendo algo de Java en el JNI además de simplemente llamar a un método, es posible que también desee presionar/abrir un marco local alrededor de esas acciones. – technomage