我正在制作这个状态/菜单栏应用程序,它在Mac OS X的状态栏中显示当前播放的歌曲。要从Spotify获取播放器状态,我必须创建并执行AppleScript并从中获取输出。然后使用Graphics2D中的drawString()绘制结果,将其设置到BufferedImage上,然后将其设置为托盘图标。
整个代码是4个类,易于理解,可在此处找到:https://github.com/ZinoKader/Menify
现在解决问题
我的运行似乎吃掉了我以前从未见过的记忆。应用程序每秒使用2-3MB的RAM,如果我离开它,则达到千兆字节。到目前为止我尝试过的是刷新和处理我的所有图像和Graphics2D资源,刷新并关闭每个输入流,输出流并销毁我在AppleScripthHelper中创建的Process对象。
即便是这样,只需调用静态方法就可以很快地开始堆积RAM。
final Runnable refreshPlayingText = () -> {
AppleScriptHelper.evalAppleScript(ScriptConstants.SPOTIFY_META_DATA_SCRIPT);
}
//update every 50ms
mainExecutor.scheduleAtFixedRate(refreshPlayingText, 0, 50, TimeUnit.MILLISECONDS);
和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();
}
}
所以问题是,吃掉所有RAM的是什么?为什么看似没有垃圾收集?
答案 0 :(得分:2)
你所面对的不是内存泄漏!
根据Java™流程和线程教程(https://docs.oracle.com/javase/tutorial/essential/concurrency/procthread.html),
流程通常具有完整的私有基本运行时资源集;特别是,每个进程都有自己的内存空间。
您每50毫秒创建一个新流程,这很可能会对您的可用内存造成影响。
创建过多的进程将导致thrashing
,您会注意到CPU性能下降。根据流程的作用,最有可能实现目标的更有效方法,而不是每秒创建20个流程。