मैं एक JNI कॉलबैक है:JNI संलग्न/अलग धागा स्मृति प्रबंधन
void callback(Data *data, char *callbackName){
JNIEnv *env;
jvm->AttachCurrentThread((void **)&env, NULL);
/* start useful code*/
/* end useful code */
jvm->DetachCurrentThread();
}
जब मैं इसे इस (खाली उपयोगी कोड) की तरह चलाने के लिए, मैं एक स्मृति रिसाव मिलता है। अगर मैं पूरी विधि पर टिप्पणी करता हूं, तो कोई रिसाव नहीं है। धागे को जोड़ने/अलग करने का सही तरीका क्या है?
मेरा एप्लिकेशन रीयल-टाइम ध्वनि डेटा को संसाधित करता है, इसलिए डेटा प्रोसेसिंग के लिए ज़िम्मेदार थ्रेड जितनी जल्दी हो सके एक और बैच के लिए तैयार होने के लिए किया जाना चाहिए। तो इन कॉलबैक के लिए, मैं नए धागे बनाते हैं। प्रत्येक सेकेंड में दर्जनों या यहां तक कि उनमें से सैकड़ों हैं, वे खुद को JVM से जोड़ते हैं, एक कॉलबैक फ़ंक्शन को कॉल करते हैं जो एक ग्राफ को दोहराता है, अलग करता है और मर जाता है। क्या यह इस सामान को करने का सही तरीका है? लीकिंग मेमोरी को कैसे संभालें?
संपादित करें: टाइपो
ठीक मैं एक mimimal कोड की जरूरत पैदा की है:
package test;
public class Start
{
public static void main(String[] args) throws InterruptedException{
System.loadLibrary("Debug/JNITest");
start();
}
public static native void start();
}
और
#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;
}
और जब मैं VisualJM प्रोफाइलर चलाने के लिए, मैं हमेशा की तरह sawtooth पैटर्न मिलता है, वहां कोई रिसाव नहीं है। हीप का उपयोग करीब 5 एमबी पर पहुंच गया। हालांकि, प्रक्रिया एक्सप्लोरर को देखते हुए वास्तव में कुछ अजीब व्यवहार दिखाते हैं: स्मृति धीरे-धीरे बढ़ रही है और बढ़ रही है, एक मिनट या 4 मिनट के लिए 4K एक सेकंड और फिर अचानक यह आवंटित स्मृति बूंदें। ये बूंदें कचरा संग्रह से मेल नहीं खाती हैं (वे अक्सर कम होते हैं और प्रोफाइलर में उन देखा-दांतों की तुलना में कम स्मृति को कम करते हैं)।
तो मेरी सबसे अच्छी शर्त यह है कि यह कुछ ओएस व्यवहार है जो हजारों मिलीसेकंद-जीवित धागे हैंडलिंग करता है। क्या कुछ गुरु के लिए इसका स्पष्टीकरण है? मूल कोड से जावा में वापस बुला के बारे में
मैं आपका बिंदु देखता हूं और मैं आम तौर पर सहमत हूं। जो धागे मैं बना रहा हूं वे वास्तव में अल्पकालिक हैं। मैं उन्हें (WinApi CreateThread का उपयोग करके) बना देता हूं, फिर तुरंत उन्हें JVM से संलग्न करता हूं।जावा में, वे एक नए मूल्य के साथ एक स्विंग ग्राफ repaint। जब वे पूरा हो जाते हैं, तो वे निष्पादन को रोकते हैं और बंद कर देते हैं (वापसी 0), जिस बिंदु पर उन्हें ओएस द्वारा नष्ट किया जाना चाहिए। वे जावा के लिए एक नया मूल्य पारित करने के लिए उपयोग किया जाता है। प्रत्येक ध्वनि चैनल के लिए उनमें से 40 प्रत्येक सेकेंड हैं (मैं 32 चैनल तक काम करता हूं)। –
आप थ्रेड पूलिंग पर विचार कर सकते हैं। अपने धागे को लंबे समय तक बने रहें और लगातार नए धागे को बढ़ाने के बजाए कतार से इनपुट लें। इससे ओएस और जावा दोनों में थ्रेड प्रबंधन ओवरहेड कम हो जाएगा। – technomage
यदि आप किसी विधि को कॉल करने के अलावा जेएनआई में कोई जावा सामान कर रहे हैं, तो आप उन कार्रवाइयों के आस-पास एक स्थानीय फ्रेम को धक्का/पॉप भी कर सकते हैं। – technomage