即使(我认为)我将Java引用设置为Null,Java也会抛出OutMfory

时间:2014-09-06 14:15:20

标签: java out-of-memory

我有一个应用程序,它会拍摄许多不同的图像,从中制作新图像,然后保存它们以用于制作视频。图像都是PNG,视频是几分钟长,因此程序需要大量内存(每33.33 MS视频播放时间一个图像)。当我处理单个视频时,一切正常。我甚至可以处理几个视频,一切正常。但是,最终,如果我尝试处理1 + n个视频,我会收到一个内存错误。

令我困惑的是这个错误是如何发生的。以下是错误发生的程序部分:

        ComposeVideoController cvc = new ComposeVideoController();          
        boolean made = cvc.setXmlUrl(sourcePath, saveDir, fileId);
        cvc = null;

更准确地说,错误发生在ComposeVideoController引用的其中一个框架构造类中。 ComposeVideoController的范围限定为递归运行的单个void方法(如果要制作更多视频)。我已经浏览了ComposeVideoController引用的所有对象,它是构建视频的库的入口点,并确保它们都被设置为null。

如果任何单个视频没有导致outofmemory错误并且在制作任何给定视频后ComposeVideoController超出范围(并设置为null),我怎么能在ComposeVideoController中得到outofmemory错误?

完整递归如下所示。我有一个方法来检查队列中是否有新消息(消息由Socket发送),如果有,则调用处理视频的方法。如果没有,则递归结束:

private void processQueue() {
    if(makingVideo) 
        return;
    MakeVideoObject mvo = queue.remove(0);      
    makingVideo = true;

    String[] convertArr = mvo.getConvertArrayCommand();
    String sourcePath = convertArr[1];
    String fileId = convertArr[2] + ".mp4";
    String saveDir = convertArr[3] + System.getProperty("file.separator");
    try {
        ComposeVideoController cvc = new ComposeVideoController();          
        boolean made = cvc.setXmlUrl(sourcePath, saveDir, fileId);
        cvc = null;
        if(made) {              
            cleanDir(mvo);
        }
    }
    catch(Exception e) {
        e.printStackTrace();
    }
}

/**
 * Moves all the assets off to a storage directory where we can be 
 * able to recover the video assets if something goes wrong during 
 * video creation.
 * 
 * @param mvo
 */
private void cleanDir(MakeVideoObject mvo) {
    String[] convertArr = mvo.getConvertArrayCommand();
    String sourceDir = convertArr[1];
    String saveDir = convertArr[3] + System.getProperty("file.separator");
    String fileId = convertArr[2];
    sourceDir = sourceDir.substring(0, sourceDir.lastIndexOf(System.getProperty("file.separator")));
    try {
        File f = new File(sourceDir);
        File[] files = f.listFiles();
        for(File file : files) {
            if(file.getName().indexOf(fileId) != -1) {
                file.renameTo(new File(saveDir + file.getName()));
            }
        }
        makingVideo = false;
        mvo = null;
        if(queue.size() > 0) {
            processQueue();
        }           
    }
    catch(Exception e) {
        e.printStackTrace();
    }
}

[编辑以显示更多节目]

3 个答案:

答案 0 :(得分:0)

几乎就是如果你递归地执行非平凡的代码会发生什么(无论是这个还是经典的堆栈溢出,以先发生者为准) - 递归是非常耗费资源的,应该不惜一切代价避免它。简单地使用迭代算法交换递归将使您的错误消失,很可能

答案 1 :(得分:0)

我发布了一个答案,因为我终于弄明白了,在这种情况下,这有助于其他人在将来尝试诊断内存泄漏。

在我的分析过程中,我可以看到内存中有对象,但是对我来说没有任何意义,因为它们被设置为null。在再次浏览其中一个对象之后,我注意到我已将其声明为静态。因为它是静态的,所以它也有静态成员,其中一个是ConcurrentHashMap ......所以,这些地图都添加了东西,因为对象是静态的,所以对象及其成员永远不会被解引用。关于为什么我几乎从不声明对象静态的另一个教训。

答案 2 :(得分:-1)

使用-Xmx增加内存空间。但是,我建议明确地调用System.gc()关于你得到OutOfMemoryException的地方......如果你把你的其他对象归零,这将有很大的帮助