使用以下递归方法时获取java.lang.OutOfMemoryError异常

时间:2018-09-05 05:57:55

标签: java recursion out-of-memory

enter image description here基本上,以下方法是遍历节点并创建类似图的结构。超过40万个对象正在创建,从而导致OutOfMemoryError。有人可以帮助优化以下代码。

方法:

    private static PolicyNodeInfo[] mapPolicySteps(PolicyTreatmentNodeInfo fromObj)
 {

    List<PolicyNodeInfo> tmpList = new ArrayList<PolicyNodeInfo>();
    PolicyTreatmentNodeInfo[] childrens = fromObj.getChildrenPolicyInfo(); 
    // Get object policy node children

    if(childrens != null) //if there are no children return empty list
    {
        for(PolicyTreatmentNodeInfo child : childrens) 
        //for each children map the object and recursively go over his children
        {
            if(null!=child)
             {
                if(X3ServerUtil.isStringNotEmptyNotNull(child.getStepName())&& 
                   !child.getStepName().startsWith("Dummy")) 
             //case child is not null (edge) or it's not non operation step (need to ignore)
                    {   
                    int index = tmpList.size();
                    tmpList.add(insertStep(child)); //insert current node

                    tmpList.get(index).setPolicyTreatmentNodeInfoList(mapPolicySteps(child)); 
                    //insert recursively all child nodes
                }
                else
                {
                handleDummyChildNodeInsertion(tmpList, child);
                }
            }
        }
    }
        return tmpList.toArray(new PolicyNodeInfo[tmpList.size()]);
}
  

异常:(Stack.java:23)   weblogic.kernel.ThreadLocalStack $ StackInitialValue.initialValue(ThreadLocalStack.java:159)   在   weblogic.kernel.FinalThreadLocal $ FinalThreadStorage。(FinalThreadLocal.java:208)   在weblogic.kernel.AuditableThread。(AuditableThread.java:13)   被截断了。请参阅日志文件以获取完整的stacktrace

图结构类似于下面的图,具有49个节点。而且由于可能有多条路径,该方法被调用了40万次以上。

4 个答案:

答案 0 :(得分:0)

对于遍历大型数据集而言,递归非常危险,因为堆栈内存实际上不受您的控制。 (换句话说:我在学校学到的递归是一种“最优雅”的解决方案,而在大学里则是“不做”-努力吧...)

要消除这种情况,请使用合适的数据结构来展开,例如这些队列:

Deque<MyObject> queue = ...
queue.push(rootElement);
while (!queue.isEmpty()) {
    MyObject currentElement = queue.poll();
    // ... process current element
    // and in the end: push children
    currentElement.getChildren().forEach(child -> queue.push(child));
}

对于深度优先遍历,请使用堆栈(即pop()代替poll());

如果这仍然给您带来内存不足的错误,则要么必须增加堆空间,要么一起使用其他方法。

答案 1 :(得分:0)

问题出在这一行tmpList.get(index).setPolicyTreatmentNodeInfoList(mapPolicySteps(child)); 这里的呼叫顺序是 mapPolicySteps(child)首先被调用,并且仅在返回<{1}}时被调用。 这样会创建很多堆栈框架,这些堆栈框架等待.setPolicyTreatmentNodeInfoList(/*Whatever returns from mapPolicySteps(child)*/)函数结束。

您需要找出一种方法,使mapPolicySteps函数最后被调用。 (称为Tail call / Tail recursion

答案 2 :(得分:0)

感谢您的帮助。一直在尝试解决此问题,并提出了以下解决方案,效果很好。在下面发布答案。 :)

  //Created a class level hashmap
public static Map<String,PolicyNodeInfo> executedElementMap=new HashMap<String,PolicyNodeInfo>();  

// Whichever node is being traversed is stored in the map.
// Before Traversing any node , just checking whether the node has already been traversed , if traversed just add the node and skip the traversing.

private static PolicyNodeInfo[] mapPolicySteps(PolicyTreatmentNodeInfo fromObj)

{
    List<PolicyNodeInfo> tmpList = new ArrayList<PolicyNodeInfo>();
    PolicyTreatmentNodeInfo[] childrens = fromObj.getChildrenPolicyInfo(); // Get object policy node children
    if(childrens != null) //if there are no children return empty list
    {
        for(PolicyTreatmentNodeInfo child : childrens) //for each children map the object and recursively go over his children
        {
            if(null!=child)
                {
                Boolean isNodeTraversed= executedElementMap.containsKey(child.getStepName());
                  if(!isNodeTraversed)
                  {
                    executedElementMap.put(child.getStepName(), child);
                    if(X3ServerUtil.isStringNotEmptyNotNull(child.getStepName())&& !child.getStepName().startsWith(PREFIX_FOR_NON_OPERATION_STEP)) //case child is not null (edge) or it's not non operation step (need to ignore)
                    {   
                        int index = tmpList.size();
                        tmpList.add(insertStep(child)); //insert current node
                        tmpList.get(index).setPolicyTreatmentNodeInfoList(mapPolicySteps(child)); //insert recursively all child nodes
                    }
                    else
                    {
                        handleDummyChildNodeInsertion(tmpList, child);
                    }
                 }  
                 else{
                      tmpList.add(insertStep(child));  
                     }
              }
        }
    }
    return tmpList.toArray(new PolicyNodeInfo[tmpList.size()]);
}

答案 3 :(得分:-1)

 I have faced same and resolved by using Garbage collector. There is multiple way to resolve this issue.
 1. Define scope of data members and make sure garbage collector is in picture.
 2. increase java memory for your Environment.
 https://www.wikihow.com/Increase-Java-Memory-in-Windows-7