Runnable和ScheduledExecutorService导致内存泄漏

时间:2022-02-15 17:32:58

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.

我正在制作这个状态/菜单栏应用程序,它在Mac OS X的状态栏中显示当前播放的歌曲。要从Spotify获取播放器状态,我必须创建并执行AppleScript并从中获取输出。然后使用来自Graphics2D的drawString()绘制结果,将其设置到BufferedImage上,然后将其设置为托盘图标。

The whole code is 4 classes and easy to follow, available here: https://github.com/ZinoKader/Menify

整个代码是4个类,易于遵循,可在此处获取: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.

我的运行似乎吃掉了我以前从未见过的记忆。每秒应用程序使用2-3MB的RAM,如果我离开它,则达到千兆字节。到目前为止我尝试过的是刷新和处理我的所有图像和Graphics2D资源,刷新并关闭每个输入流,输出流并销毁我在AppleScripthHelper中创建的Process对象。

Even something like this, just calling a static method starts piling up RAM really quickly.

即使是这样的事情,只需调用静态方法就可以很快地开始堆积RAM。

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?

所以问题是,吃掉所有RAM的是什么?为什么看似没有垃圾收集?

1 个解决方案

#1


2  

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),

根据Java™流程和线程教程(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.

您每50毫秒创建一个新进程,这很可能会对您的可用内存产生影响。

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.

创建过多的进程会导致颠簸,您会发现CPU性能下降。根据流程的作用,很有可能是一种更有效的方法来实现您的目标,而无需每秒创建20个流程。

#1


2  

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),

根据Java™流程和线程教程(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.

您每50毫秒创建一个新进程,这很可能会对您的可用内存产生影响。

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.

创建过多的进程会导致颠簸,您会发现CPU性能下降。根据流程的作用,很有可能是一种更有效的方法来实现您的目标,而无需每秒创建20个流程。