I'm making this status/menu bar app which displays the currently playing song in the status bar for Mac OS X. To get the player status from Spotify I have to create and execute an AppleScript and get the output from this. The result is then drawn using drawString() from Graphics2D, which is set onto a BufferedImage which is then set as the tray icon.
The whole code is 4 classes and easy to follow, available here: https://github.com/ZinoKader/Menify
Now onto the problem
My runnable seems to eat up memory like nothing I've seen before. Every second the application uses 2-3MB more RAM, and reaches for gigabytes if I leave it be. What I have tried so far is to flush and dispose of all my images and Graphics2D resources, flush and close every inputstream, outputstream and destroy the Process object I create in AppleScripthHelper.
Even something like this, just calling a static method starts piling up RAM really quickly.
final Runnable refreshPlayingText = () -> {
AppleScriptHelper.evalAppleScript(ScriptConstants.SPOTIFY_META_DATA_SCRIPT);
}
//update every 50ms
mainExecutor.scheduleAtFixedRate(refreshPlayingText, 0, 50, TimeUnit.MILLISECONDS);
and AppleScriptHelper
class AppleScriptHelper {
private static final int EOF = -1;
static String evalAppleScript(String code) {
String[] args = { "osascript", "-e", code };
try {
Process process = Runtime.getRuntime().exec(args);
process.waitFor();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] bigByteArray = new byte[4096];
InputStream is = process.getInputStream();
copyLargeStream(is, baos, bigByteArray); //write to outputstream
String result = baos.toString().trim();
is.close();
baos.flush();
baos.close();
process.destroyForcibly();
return result;
} catch (IOException | InterruptedException e) {
Log.debug(e);
return null;
}
}
private static void copyLargeStream(InputStream input, OutputStream output, byte[] buffer) throws IOException {
int n;
while (EOF != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
input.close();
output.close();
}
}
So the question is, what is eating up all of that RAM? Why is seemingly nothing being garbage collected?
What you're facing is not a memory leak!
According to the Java™ Tutorials for Processes and Threads ( https://docs.oracle.com/javase/tutorial/essential/concurrency/procthread.html ),
A process generally has a complete, private set of basic run-time resources; in particular, each process has its own memory space.
You're creating a new process every 50ms which is most likely what is taking a toll on your available memory.
Creating too many processes will result in thrashing
and you will notice reduced CPU performance. Depending on what the process does, there is most likely a more efficient way to achieve your goal without creating 20 processes per second.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.