2010-05-08 72 views
1

有一个处理实时数据的应用程序,当某个事件发生时应该会发出蜂鸣声。触发事件每秒可能发生多次,如果哔声已经在播放,而另一个事件触发代码则应该忽略它(而不是中断当前的嘟嘟声并开始新的哔声)。这是基本的代码:我是否需要关闭音频剪辑?

Clip clickClip 

public void prepareProcess() { 
    super.prepareProcess(); 

    clickClip = null; 

    try { 
     clipFile = new File("C:/WINDOWS/Media/CHIMES.wav"); 
     ais = AudioSystem.getAudioInputStream(clipFile); 
     clickClip = AudioSystem.getClip(); 
     clickClip.open(ais); 

     fileIsLoaded = true; 

    } catch (Exception ex) { 
     clickClip = null; 
     fileIsLoaded = false; 
    } 
} 

public void playSound() { 

    if (fileIsLoaded) { 

     if ((clickClip==null) || (!clickClip.isRunning())) { 

      try { 
       clickClip.setFramePosition(0); 
       clickClip.start(); 
      } catch (Exception ex) { 
       System.out.println("Cannot play click noise"); 
       ex.printStackTrace(); 
      } 
     } 
    } 

的prepareProcess的方法获取开始时运行一次,playSound方法被调用每一个触发事件发生的时间。我的问题是:我需要关闭clickClip对象吗?我知道我可以添加一个actionListener来监视Stop事件,但由于事件频繁发生,我担心额外的处理会减慢实时数据收集。

该代码似乎运行良好,但我担心的是内存泄漏。上面的代码基于我在搜索网络时找到的示例,但该示例使用actionListener专门关闭Clip以“消除停止方法未实现时会发生的内存泄漏”。我的程序打算运行几个小时,所以任何内存泄漏都会导致问题。

我会说实话:我不知道如何验证我是否有问题。我使用的是Netbeans,运行内存分析器只是给了我一大堆我不知道如何阅读的东西。这应该是该计划的一个简单部分,我花了几个小时。任何帮助将不胜感激!

迈克尔

回答

0

在Java内存泄漏有甚至在其使用寿命已经结束的是仍然被引用的对象做。在很多情况下,这将是由于重复制作50个对象,但仅仅消除了其后的49个对象的引用。

在你的代码中似乎没有这样的事情发生。由于prepareProcess()只运行一次,因此不存在高度怀疑。这留下了playSound(),它根本不包含任何对象实例,更不用说错误的引用消除循环。

需要注意的是,我不确定声音片段对象幕后发生了什么,而且很难检查,因为majuscule-C Clip只是一个界面。但是,除非你使用第三方代码,否则我会很惊讶地发现泄漏。

长话短说,我不会担心它,除非你真的看到类似OutOfMemoryError的东西。

+0

非常感谢回复。我同意你的看法,根据我给的代码,这似乎不成问题。但是(如你所说)我不知道Clip对象背后发生了什么。通过Netbeans内存分析器可以更多地发现,每次播放声音时都会分配一个新对象。但是,Live Object列永远不会增加,所以我假设这意味着垃圾收集立即处理它。奇怪的行为,但我会确保在测试过程中观看它,以确保它没问题。 再次感谢。 Michael – Michael 2010-05-11 05:16:44

4

是,关闭是必要

myClip.addLineListener(new LineListener() { 
    public void update(LineEvent myLineEvent) { 
     if (myLineEvent.getType() == LineEvent.Type.STOP) 
     myClip.close(); 
    } 
    }); 

if (!myClip.isRunning()) 
    myClip.close(); 

在我的应用程序(util.concurrent程序来临之前写的),这是剪辑关闭机构。

public static final Vector<Clip> vector = new Vector<Clip>(); 
    static final int vector_size = 5; 

    // typically called before calling play() 
    static synchronized void consolidate() { 
    while (vector_size < vector.size()) { 
     Clip myClip = vector.get(0); 
     if (myClip.isRunning()) 
     break; 
     myClip.close(); 
     vector.remove(0); 
    } 
    if (vector_size * 2 < vector.size()) 
     System.out.println("warning: audio consolidation lagging"); 
    } 

    public static void play(final File myFile) { 
    try { 
     AudioInputStream myAudioInputStream = AudioSystem.getAudioInputStream(myFile); 
     final Clip myClip = AudioSystem.getClip(); 
     vector.add(myClip); 
     myClip.open(myAudioInputStream); 
     myClip.start(); 
    } catch (Exception myException) { 
     myException.printStackTrace(); 
    } 
    } 

作为一个评论暗示,它可能会推迟新的剪辑播放,但我不记得在数毫秒的延迟并不在我的应用程序非常重要。

+1

您的答案的基本原理是什么?为什么有必要?有什么好处? – pstanton 2013-07-08 11:44:10

+0

如果你不关闭剪辑,一切都会好起来的,直到你的程序崩溃,因为内存不足的瓶颈。这是我遇到这个问题的应用程序:[link](http://www.youtube.com/watch?v=3F06TdnnOjQ) – datahaki 2013-07-13 17:30:29

+0

有趣。我发现关闭剪辑很昂贵,并且在播放处于活动状态时(使用另一个剪辑)会导致延迟。我将不得不测试理论垃圾收集,并且可能在所有音频播放空闲时批量关闭剪辑。你有没有注意到关闭时的延迟,你是如何克服这一点的? – pstanton 2013-07-13 21:42:40