Как обрабатывать StackOverflowError, возникающий при сериализации большого объекта? - PullRequest
0 голосов
/ 16 марта 2012

Вот мой код Java:

    FileOutputStream fos = null; 
    ObjectOutputStream out = null;
    try {
        fos = new FileOutputStream(pathName);
        out = new ObjectOutputStream(fos);
        out.writeObject(index);
        out.close();
        fos.close();
    } catch (IOException e) {
        LogManager.writeLogToFile(e.getMessage());
        e.printStackTrace();
    }

Индекс является экземпляром перевернутого индекса документа самостоятельно. Я построил индекс объекта в памяти, но когда я передаю его методу writeObject (index), я получаю ошибку StackOverflowError. У меня вопрос: почему эта ошибка возникает после того, как я построил объект в памяти?

Предположим, что структура данных индекса следующая:

class InvertedIndex{
    private HashMap<String, PostList> index;
}
class PostList{
    private int size;
    private PostNode first;
}
class PostNode{
    private String key;
    private double weight;
    private PostNode next;
}

Чтобы избежать рекурсивного вызова, я перезаписываю методы writeObject и readObject из PostList, потому что это может быть очень длинный список:

class PostList{
     private void writeObject(ObjectOutputStream out) throws IOException{
            PostNode temp = first;
            while(temp != null){
                  out.writeObject(temp);
                  temp = temp.getNext();
            }
     }
     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
            in.defaultReadObject();
    }
}

Тогда я получу два вопроса:

  • out.writeObject (температура); Поскольку у temp есть ссылка на следующий узел, когда я пишу temp, также произойдет рекурсивный вызов. Та же ситуация будет продолжаться, даже если я перезапишу метод writeObject объекта PostNode с параметром defaultWriteObject. Я прав? Если так, что я могу сделать, чтобы избежать этого рекурсивного вызова?
  • Как переписать метод readObject ()?

Ответы [ 3 ]

1 голос
/ 16 марта 2012

Трудно понять, не видя сериализуемый класс, но я думаю, что граф объектов слишком сложен. Механизм сериализации по умолчанию в Java работает рекурсивно по графу объектов; то есть, если у вас есть объект A со ссылкой на B, и вы сериализуете A, ему придется перейти к B и сериализовать его. Если B затем ссылается на C, а C ссылается на D и т. Д., То для рекурсивного алгоритма возможно оказаться настолько глубоким, что он вызовет переполнение стека.

Если это является причиной вашей проблемы, вы должны написать свои собственные readObject и writeObject, которые по возможности избегают этого рекурсивного построения.

0 голосов
/ 17 марта 2012

Ваш метод readObject () не соответствует вашему методу writeObject (), поэтому он, вероятно, вообще не работает, а ваш метод writeObject () не добавляет никакого значения в сериализацию по умолчанию. Тебе было бы лучше без обоих.

Проблема рекурсии возникает из класса PostNode, а не из класса PostList, и вы фактически ничего с этим не сделали. Вам нужен PostNode.writeObject (), который явно просматривает список, и симметричный метод readObject (), и временное поле «next».

0 голосов
/ 16 марта 2012

Если у вас глубоко вложенная структура объектов, то для обхода потребуется глубокий стек. Вы должны увидеть это в трассировке стека исключений. ObjectOutputStream и ObjectInputStream не особенно скромны с пространством стека.

Если вы пытаетесь сериализовать что-то вроде связанного списка, то лучше реализовать методы readObject и writeObject, которые выполняют итерацию по списку, а не повторяют.

...