मैं जावा एप्लिकेशन बनाने की प्रक्रिया में हूं जो लंबे समय तक चल रहा है जिसके लिए बिना बंद किए अद्यतन की कार्यक्षमता की आवश्यकता होती है। मैंने इस अद्यतन कार्यक्षमता को .java फ़ाइलों के रूप में लोड करके (डेटाबेस से बाइट सरणी के रूप में खींचा) प्रदान करने का निर्णय लिया है जो स्मृति और त्वरित में संकलित हैं। यदि आपके पास बेहतर तरीका है तो मैं सभी कान हूं।जावा लोडिंग और अनलोडिंग .java फ़ाइलें गतिशील रूप से, कचरा संग्रह?
जिस समस्या में मैंने भाग लिया है वह यह है कि जब मैं कृत्रिम वातावरण में कुछ परीक्षण करता हूं तो इन "स्क्रिप्ट" को लोड करने के प्रत्येक चक्र के साथ मेमोरी पदचिह्न थोड़ा बढ़ता है।
नोट: यह वास्तव में मेरा पहला समय जावा या बिल्कुल कुछ ऐसा करने जैसा है। मैंने लोडिंग और अनलोडिंग .cs फ़ाइलों के साथ सी # में पहले ऐसा कुछ हासिल किया था और मेमोरी पदचिह्न के मुद्दों को भी हल किया था ... हल करने के लिए कि मैंने उन्हें एक अलग ऐपडोमेन में लोड किया और जब मैंने फ़ाइलों को दोबारा बनाया, तो मैंने उस ऐपडोमेन को उतार दिया और बनाया नया।
प्रवेश बिंदु
इस प्रविष्टि विधि है कि मैं का उपयोग करें (कई recompile चक्र) की लंबी अवधि के बाद स्मृति पदचिह्न अनुकरण करने के लिए उपयोग कर रहा हूँ है। मैं इसे थोड़े समय के लिए चलाता हूं और यह जल्दी से 500 एमबी + खाता है।
यह अस्थायी निर्देशिका में केवल दो डमी स्क्रिप्ट के साथ है।
public static void main(String[ ] args) throws Exception {
for (int i = 0; i < 1000; i++) {
Container[ ] containers = getScriptContainers();
Script[ ] scripts = compileScripts(containers);
for (Script s : scripts) s.Begin();
Thread.sleep(1000);
}
}
लिपियों (अस्थायी) की एक सूची एकत्रित
यह अस्थायी विधि मैं स्क्रिप्ट फ़ाइलों की एक सूची इकट्ठा करने के लिए उपयोग कर रहा हूँ है। उत्पादन के दौरान इन्हें वास्तव में बाइट एरे के रूप में लोड किया जाएगा, जिसमें कुछ अन्य जानकारी जैसे डाटाबेस से कक्षा का नाम होता है।
@Deprecated
private static Container[ ] getScriptContainers() throws IOException {
File root = new File("C:\\Scripts\\");
File[ ] files = root.listFiles();
List<Container> containers = new ArrayList<>();
for (File f : files) {
String[ ] tokens = f.getName().split("\\.(?=[^\\.]+$)");
if (f.isFile() && tokens[ 1 ].equals("java")) {
byte[ ] fileBytes = Files.readAllBytes(Paths.get(f.getAbsolutePath()));
containers.add(new Container(tokens[ 0 ], fileBytes));
}
}
return containers.toArray(new Container[ 0 ]);
}
कंटेनर वर्ग
यह सरल कंटेनर वर्ग है।
public class Container {
private String className;
private byte[ ] classFile;
public Container(String name, byte[ ] file) {
className = name;
classFile = file;
}
public String getClassName() {
return className;
}
public byte[ ] getClassFile() {
return classFile;
}
}
लिपियों
यह वास्तविक विधि है कि जावा फ़ाइलों संकलित करता है तथा स्क्रिप्ट वस्तुओं में को दर्शाता है संकलन।
private static Script[ ] compileScripts(Container[ ] containers) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
List<ClassFile> sourceScripts = new ArrayList<>();
for (Container c : containers)
sourceScripts.add(new ClassFile(c.getClassName(), c.getClassFile()));
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
JavaFileManager manager = new MemoryFileManager(compiler.getStandardFileManager(null, null, null));
compiler.getTask(null, manager, null, null, null, sourceScripts).call();
List<Script> compiledScripts = new ArrayList<>();
for (Container c : containers)
compiledScripts.add((Script)manager.getClassLoader(null).loadClass(c.getClassName()).newInstance());
return (Script[ ])compiledScripts.toArray(new Script[ 0 ]);
}
MemoryFileManager वर्ग
यह कस्टम JavaFileManager कार्यान्वयन है कि मैं संकलक के लिए बनाए गए ताकि मैं स्मृति में के बजाय शारीरिक .class फ़ाइलों में उत्पादन स्टोर कर सकते हैं है।
public class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
private HashMap< String, ClassFile > classes = new HashMap<>();
public MemoryFileManager(StandardJavaFileManager standardManager) {
super(standardManager);
}
@Override
public ClassLoader getClassLoader(Location location) {
return new SecureClassLoader() {
@Override
protected Class<?> findClass(String className) throws ClassNotFoundException {
if (classes.containsKey(className)) {
byte[ ] classFile = classes.get(className).getClassBytes();
return super.defineClass(className, classFile, 0, classFile.length);
} else throw new ClassNotFoundException();
}
};
}
@Override
public ClassFile getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) {
if (classes.containsKey(className)) return classes.get(className);
else {
ClassFile classObject = new ClassFile(className, kind);
classes.put(className, classObject);
return classObject;
}
}
}
classfile वर्ग
यह मेरा बहुउद्देश्यीय SimpleJavaFileObject कार्यान्वयन है कि मैं स्मृति में स्रोत जावा फ़ाइलें और .class संकलित फ़ाइलों को स्टोर करने के लिए उपयोग है।
public class ClassFile extends SimpleJavaFileObject {
private byte[ ] source;
protected final ByteArrayOutputStream compiled = new ByteArrayOutputStream();
public ClassFile(String className, byte[ ] contentBytes) {
super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
source = contentBytes;
}
public ClassFile(String className, CharSequence contentCharSequence) throws UnsupportedEncodingException {
super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
source = ((String)contentCharSequence).getBytes("UTF-8");
}
public ClassFile(String className, Kind kind) {
super(URI.create("string:///" + className.replace('.', '/') + kind.extension), kind);
}
public byte[ ] getClassBytes() {
return compiled.toByteArray();
}
public byte[ ] getSourceBytes() {
return source;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws UnsupportedEncodingException {
return new String(source, "UTF-8");
}
@Override
public OutputStream openOutputStream() {
return compiled;
}
}
स्क्रिप्ट इंटरफ़ेस
और अंत में सरल स्क्रिप्ट इंटरफ़ेस।
public interface Script {
public void Begin() throws Exception;
}
मैं अभी भी नई तरह की है जब यह प्रोग्रामिंग करने के लिए आता है और मैं छोटे समस्याओं मैं सामना करना पड़ा करने के लिए कुछ समाधान खोजने के लिए थोड़ी देर के लिए ढेर का इस्तेमाल किया है कर रहा हूँ, यह मेरी पहली बार एक सवाल इसलिए पूछ रहा माफी माँगता है अगर मैंने बहुत अधिक जानकारी शामिल की है या यदि यह बहुत लंबा है; मैं बस यह सुनिश्चित करना चाहता था कि मैं पूरी तरह से था।
आप स्मृति पदचिह्न को कैसे मापते हैं? जावा में, प्रोग्राम वास्तव में * कितनी मेमोरी * का उपयोग करता है, और यह कितना * उपयोग के लिए आरक्षित * के बीच एक गहरा अंतर है। एक अच्छी तरह से रखे प्रश्न के लिए –
+1, मुझे इसका जवाब देखने में दिलचस्पी है। क्या आपने मौका से जावा प्रतिबिंब देखा है? – FloppyDisk
मैं अपने टास्क मैनेजर में विशिष्ट javaw.exe प्रक्रिया के लिए बढ़ी हुई स्मृति उपयोग को ध्यान में रखते हुए एक्लिप्स मेमोरी विश्लेषक का उपयोग कर रहा था। ऐसा लगता है कि कचरा कलेक्टर अप्रयुक्त अवशेषों को इकट्ठा करने के लिए कुछ भी नहीं कर रहा है ... इसके अलावा यह भी तथ्य है कि अगर मैं नींद को हटा देता हूं और इसे (सत्य) पर सेट करता हूं तो यह स्मृति से बाहर दुर्घटनाग्रस्त हो जाता है। – Jordan