2016-01-07 90 views
-1

此代碼中的問題是垃圾收集器(GC)永遠不會刪除由產品引用的對象。我可以通過在Eclipse的調試器中將該對象視爲活動實例來驗證此情況。垃圾收集器永遠不會刪除對象

public static List<ConditionalProbabilityTable> sumOut(List<ConditionalProbabilityTable> factorization, List<Variable> varsToSumOut) { 

    List<ConditionalProbabilityTable> newFactorization = new ArrayList<>(factorization); 

    for (Variable varToSumOut : varsToSumOut) { 
     List<ConditionalProbabilityTable> relevantCpts = Inference.getAllCptsContaining(newFactorization, varToSumOut); 
     ConditionalProbabilityTable product = Inference.multiplyAll(relevantCpts); 

     ConditionalProbabilityTable marginal = ConditionalProbabilityTableOperation.marginalize(product, varToSumOut); 
     newFactorization.removeAll(relevantCpts); 
     newFactorization.add(marginal); 
    } 

    return newFactorization; 
} 

如果我沒看錯的,由產品所指向的對象被保持活着,因爲一些參考吧(或者產品的成員的引用)也是活的。但我找不到這樣的參考(如果需要,我可以添加更多的代碼)。

我的目標是擺脫產品指出的對象。

編輯

遵循ConditionalProbabilityTableOperation.marginalize代碼:

public static ConditionalProbabilityTable marginalize(ConditionalProbabilityTable cpt, Variable variable) { 
    ConditionalProbabilityTable marginalCpt = new ConditionalProbabilityTable(); 

    // Determine the scope of the new CPT. 
    List<Variable> marginalCptLeftVariables = new ArrayList<>(); 
    marginalCptLeftVariables.addAll(cpt.getLeft()); 
    marginalCptLeftVariables.remove(variable); 
    marginalCpt.addAllToLeft(marginalCptLeftVariables); 

    List<Variable> marginalCptRightVariables = new ArrayList<>(); 
    marginalCptRightVariables.addAll(cpt.getRight()); 
    marginalCptRightVariables.remove(variable); 
    marginalCpt.addAllToRight(marginalCptRightVariables); 

    // Summation loop 
    int j = 0; 
    int[] assignments = new int[cpt.getNumberOfVariables()]; 
    int numberOfRowsInMarginal = marginalCpt.getNumberOfRows(); 
    List<Double> marginalValues = new ArrayList<>(Collections.nCopies(numberOfRowsInMarginal, 0.0)); 

    for (int i = 0; i < cpt.getNumberOfRows(); i++) { 
     marginalValues.set(j, marginalValues.get(j) + cpt.getValue(i)); 

     for (int l = 0; l < cpt.getNumberOfVariables(); l++) { 
      assignments[l] = assignments[l] + 1; 
      int lVarCard = cpt.getVariable(l).getCardinality(); 
      if (assignments[l] == lVarCard) { 
       assignments[l] = 0; 
       j = j - (lVarCard - 1) * marginalCpt.getStride(cpt.getVariable(l)); 
      } else { 
       j = j + marginalCpt.getStride(cpt.getVariable(l)); 
       break; 
      } 
     } 
    } 

    marginalCpt.setValues(marginalValues); 


    return marginalCpt; 
} 

解決方案

繼@使用內存分析器,我可以識別由product在YourKit指向的對象the8472建議內存快照。令人驚訝的是,在for循環之後,該對象消失了!這意味着可能調試器確實以某種方式保持對象(如本線程中的其他人所建議的那樣),停止GC去除它。對我來說,這是令人驚訝的,因爲我已經在類似上下文中的一個小例子之前運行,並且調試器在該例子中沒有保留該對象。我不明白爲什麼它沒有保持這個時間,並堅持在這一個,但無論如何,它似乎是調試器故障。 非常感謝您的支持。

+1

ConditionalProbabilityTableOperation.marginalize()的內部是什麼? – Wash

+0

'ConditionalProbabilityTableOperation.marginalize'是否保留對'product'的引用? –

+0

'邊際'如何構建?您是否在使用產品中的任何成員參考? –

回答

0

使用內存分析器,創建堆轉儲,查找有問題的對象,檢查從這些對象到gc根的路徑。

準確的步驟取決於探查器/轉儲分析器工具。

+0

感謝您的建議,@ the8472。其實,在使用YourKit之前我已經嘗試過了(我以一種非常簡單的方式使用,我對這些技術沒有深入的瞭解)。這裏的問題是我無法確定我應該跟蹤哪個對象。在轉儲中,我會有很多'ConditionalProbabilityTable'對象,但我找不到一種方法來檢測與for循環中的'product'相關的特定對象。你有什麼想法嗎? – jhonatanoliveira

+0

使用yourkit,您可以*爲該類別列出GC路徑*的組合路徑。如果這個特定的循環與其他所有對象有所不同,那麼執行線程中的局部變量應該顯示爲一個根。 – the8472

+0

按照您的建議,我可以在YourKit內存快照中識別'product'指向的對象。令人驚訝的是,在for循環之後,該對象消失了!這意味着調試器可能以某種方式保持對象,阻止GC將其移除。對於我來說,這是令人驚訝的,因爲我在類似的情況下運行了一個小例子,調試器在該例中沒有保留該對象。我不明白爲什麼它沒有保持這個時間,並堅持在這一個,但無論如何,它似乎是調試器故障。我現在就關閉這個線程。謝謝。 – jhonatanoliveira