簡體   English   中英

Java拋出內存不足,即使(我認為)我將引用設置為Null

[英]Java Throwing OutOfMemory Even Though (I Think) I've Set References To Null

我有一個應用程序,該應用程序可以拍攝許多不同的圖像,從它們中制作新圖像,然后將其保存以用於制作視頻。 圖像都是PNG格式,而視頻則是幾分鍾,因此該程序需要大量內存(每33.33 MS視頻播放時間一張圖像)。 當我處理單個視頻時,一切正常。 我什至可以處理多個視頻,而且一切正常。 但是,如果我嘗試處理1 + n個視頻,最終會出現內存不足的錯誤。

使我困惑的是該錯誤是如何發生的。 這是程序中發生錯誤的部分:

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

更准確地說,該錯誤發生在ComposeVideoController引用的其中一個幀構造類中。 ComposeVideoController的作用域是遞歸運行的單個void方法(如果要制作更多視頻)。 我已經遍歷了ComposeVideoController引用的所有對象,這是構建視頻的庫的入口點,並確保它們也都設置為null。

當制作任何給定視頻后,任何單個視頻都不會引起內存不足錯誤並且ComposeVideoController超出范圍(並將其設置為null)時,如何在ComposeVideoController中出現內存不足錯誤?

完整的遞歸如下所示。 我有一種方法可以檢查隊列中是否有新消息(消息是由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();
    }
}

[編輯以顯示更多程序]

如果您遞歸地執行非平凡的代碼(這是經典堆棧溢出還是經典堆棧溢出,以先發生者為准),那幾乎就是什么-遞歸非常占用資源,應該不惜一切代價避免它。 只需使用迭代算法交換您的遞歸,您的錯誤就很可能消失

我發布了答案,因為我終於弄清楚了,如果情況不妙,這將有助於其他人將來嘗試診斷內存泄漏。

在分析過程中,我可以看到內存中保留有對象,但是對我來說這沒有意義,因為它們被設置為null。 再次瀏覽了其中一個對象之后,我注意到我已將其聲明為靜態。 因為它是靜態的,所以它也有靜態成員,其中之一是ConcurrentHashMap ...因此,那些Map中添加了一些東西,並且由於對象是靜態的,因此永遠不會取消引用該對象及其成員。 關於為什么我幾乎從不聲明對象靜態的另一個教訓。

使用-Xmx可以增加您的內存空間。 而且,我建議您在正確的位置顯式地調用System.gc(),以獲取OutOfMemoryException ...如果要清空其他對象,這將對您有很大幫助

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM