线程不释放内存

时间:2014-04-28 19:04:08

标签: java multithreading audio memory-leaks garbage-collection

  

我试图在我的程序中使用线程播放声音效果,我搜索了网络,据我所知,当一个线程到达运行功能的末尾时,GC将自由收集。

     

然而,当我一个接一个地多次调用该函数时,任务管理器显示内存使用量大幅增加而且它从未退回,我等了2分钟就没有效果。

以下是我用来播放音效的代码:

public static void playSfx(final String path) {
    new Thread(new Runnable() {
        public void run() {
            try {
                AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(path));

                final int BUFFER_SIZE = 128000;
                SourceDataLine sourceLine = null;

                AudioFormat audioFormat = audioInputStream.getFormat();
                DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);

                sourceLine = (SourceDataLine) AudioSystem.getLine(info);
                sourceLine.open(audioFormat);

                if (sourceLine == null)
                    return;

                sourceLine.start();
                int nBytesRead = 0;
                byte[] abData = new byte[BUFFER_SIZE];
                while (nBytesRead != -1) {
                    try {
                        nBytesRead = audioInputStream.read(abData, 0, abData.length);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    if (nBytesRead >= 0) {
                        sourceLine.write(abData, 0, nBytesRead);
                    }
                }

                sourceLine.drain();
                sourceLine.close();
                audioInputStream.close();

            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(1);
            }
        }
    }).start();
}

我该怎样做才能收回丢失的记忆?

2 个答案:

答案 0 :(得分:0)

我无法重现这一点。对我而言,这将达到大约60k内存使用率的峰值 考虑到有问题的语言是完全可以的imo。你有什么小事 可靠地再现问题的代码?

public static void main(String[] args) {
    for(int i = 0; i < 1000; i++) {
        playSfx("somesortsound.wav");
        try {
            Thread.sleep(100);
        } catch (Exception e) {
        }
    }
}

此外,您对内存使用的期望是什么?预测GC 行为并不容易,而且你不能保证看到内存被释放只是因为 你等一会儿。特别是如果你没有分配很多。

我也会在你的阅读循环中摆脱try catch。你不处理任何事情 无论如何都有例外,你也可以在循环外捕获它。如果 stream导致IO异常你想要中止循环,对吧?

答案 1 :(得分:0)

使用兼容文件从以下类运行该方法,没有任何异常;我没有看到这种行为。

public class PlaySound {

public static void main(String[] args) throws Exception {
    String filePath = "C:"+File.separator+"bach.wav"; 
    playSfx(filePath);
    playSfx(filePath);
    playSfx(filePath);
    while(true){
        Thread.sleep(1000);
    }
}
}

可能是内存泄漏。您没有使用finally块(或“try-with-resources”)管理资源,将此与return语句耦合可能会导致AudioInputStream驱动程序的内部维护对文件的引用。

我会使用try-with-resources块。

 try(AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(path));){
   //your code
}

另外,我不会使用任务管理器来可靠地确定垃圾收集器的行为,有许多组件可以确定内存中Java进程的大小。

了解正在发生的事情;使用VisualVM。 (它位于jdk的bin目录中)。您可以看到垃圾收集器处于活动状态的时间,以及堆的大小与其当前最大大小的比较。您还可以“请求”(不保证)垃圾收集,这将指示“幸存者”所需的内存量以及可以释放的数量。

不可否认,2分钟是很长一段时间,但值得一提的是,垃圾收集通常是因为未能将内存分配给特定代,但这取决于所使用的特定GC算法。换句话说,如果它没有达到上限,则有可能它不会执行垃圾收集。

This article可能值得阅读/浏览;它详细介绍了各种不同的垃圾收集器以及它们如何运行。