2014-04-28 104 views
0

我想在我的程序中使用线程播放音效,我搜索了网页,并且据我了解,当线程到达运行函数结束时,它将变成免费的GC搜集。线程不释放内存

但是,当我多次调用函数时,任务管理器显示内存使用量增加很多,并且它永远不会回落,我等待了2分钟的GC,但没有任何效果。

这里是我使用的播放音效代码:

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(); 
} 

我应该怎么做来收回失去的记忆?

+0

是什么让你觉得内存是*丢失*?你不使用它,所以无论它看起来像分配还是空闲都没关系。所以,JVM和你的操作系统都不要求释放内存,除非你需要*它。 – Holger

回答

0

我不能重现这一点。对我来说,这将达到约60k的内存使用率,其中 考虑到有问题的语言是完全可以的。你有没有可靠地再现问题的小码 ?

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。不管怎样,你都不会处理任何异常,并且你也可以在循环外捕获它。如果 流导致IO异常,你是否想要中止循环,对吧?

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可能值得一读/浏览;它详细介绍了各种不同的垃圾收集器以及它们如何运作。