2016-05-04 4 views
2

У меня есть обычная 64-битная Jots Jots, которая имеет размер стека 1 МБ. Теперь я пытался сериализовать объект, который имеет иерархию из 3022 родителей, и это дает мне исключение SO (ирония).Спецификация размера стека JVM

Вот код:

while(epc.getParent()!=null){ 

     epc=epc.getParent(); 
     count++; 
    } 
    print(count);//3022 

Приведенный выше код просто сказать иерархию, но фактическая проблема возникает, когда я пытаюсь сериализации epc объект на ObjectOutputStream.

Вопрос: Что делает состояние стека 1 МБ в JVM, поскольку я понятия не имею, какой размер представляет собой стек? Я уверен, что это не 1 Кбайт в кадре стека, потому что я успешно закончил код на -Xss3000k.

Еще один вопрос, имеет ли каждый поток размер стека 3000k, если я ставлю JVM-параметр -Xss3000k?

+0

Не могли бы вы рассказать о том, «что делает размер стека 1 МБ в JVM», это не очень понятно. –

+0

Этот код не похож, он должен потреблять много пространства стека. Как работает 'getParent()'? «Сериализовать объект» означает «записать его в ObjectOutputStream»? – Thilo

+0

@ RazvanManolescu Я хотел знать, может ли 1 MB обрабатывать сериализацию объекта с родительской иерархией из 3022 родителей? –

ответ

10

Вопрос, что делает состояние 1 MB размера стека в JVM, как я понятия не имею, что размер стек кадр?

Размер стека по умолчанию в 1 МБ означает, что каждый поток имеет 1 МБ (1048576 байт) пространства стека ... по умолчанию. Исключением является, если ваш код создает поток, используя один из конструкторов Thread, где вы можете предоставить аргумент размера стека.

Размер фрейма стека зависит от вызываемого метода. Он должен содержать параметры метода и локальные переменные, поэтому размер кадра зависит от их размера.Для каждого кадра также требуется (я думаю) два дополнительных слова для хранения сохраненного указателя кадра и сохраненного обратного адреса.

Обратите внимание, что в рекурсивном алгоритме у вас может быть несколько кадров стека для одного «уровня рекурсии». Для writeObject (в Java 8), алгоритм, используемый рекурсивно, и, как правило, 4 кадра в уровне структуры данных сериализации:

writeObject0 
writeOrdinaryObject 
writeSerialData 
defaultWriteFields 
writeObject0 
etcetera 

Фактические размеры кадров будет зависеть платформа из-за различий в трансляторов, и изменения в реализации ObjectInputStream/ObjectOutputStream. Вам лучше попытаться (грубо) измерить требуемое пространство стека, а не пытаться предсказать размеры кадров с первых принципов.

Еще один вопрос, имеет ли каждый поток размер стека 3000k, если я ставлю JVM-параметр -Xss3000k?

Да ... за исключением того, что я описал выше.

Одним из возможных решений вашей дилеммы является создание специального потока с огромным стеком, который вы используете для сериализации. Для десериализации потребуется подобный поток с огромным стеклом. Для остальных потоков размер стека по умолчанию должен быть точным.

Другие возможные решения:

  • Реализовать writeReplace и readResolve методы для выравнивания родительской структуры ваших объектов ЕРС в массив, так что вы не получите глубокую рекурсию. (Очевидно, что уплощение/unflattening должно быть сделано нерекурсивно.)

  • Сделайте то же самое уплощение перед тем вы звоните writeObject, и так далее.

  • Используйте другой механизм сериализации или пользовательский.

+1

Следует подчеркнуть, что управление сериализацией графа объектов путем увеличения размера стека потребует также увеличенного размера стека на конце десериализации и, как вы правильно заметили, точное требование будет специфичным для реализации. – Holger

+0

@ Хольджер хорошая точка. Обновлено. –

2

Имеет ли каждый поток размер стека 3000k, если я устанавливаю JVM-опцию -Xss3000k?

Существует a constructor to specify the stack size для новой темы. Все потоки, которые не используют этот специальный конструктор, получат размер стека по умолчанию, указанный в опции JVM (и это будет охватывать все потоки, если вы не создадите их явно).

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

Если нет, вы можете создать такой поток большого стека, особенно для запуска кода с глубокой рекурсивной сериализацией. Вы можете завернуть его в Исполнителя и вызвать в него код приложения.

Что делает состояние стека 1 МБ в JVM, поскольку я не знаю, какой размер представляет собой стек?

Это действительно немного движущаяся цель. Вы должны сделать это настраиваемым, и эксперименты расскажут вам, какая хорошая настройка.

Даже Javadoc говорит

В связи с платформы зависит характер поведения этого конструктора, крайняя осторожность следует проявлять при его использовании. Размер стека потоков, необходимый для выполнения данного вычисления, вероятно, будет отличаться от одной реализации JRE к другой. В свете этого варианта может потребоваться тщательная настройка параметра размера стека, и настройка может потребоваться повторить для каждой реализации JRE, на которой должно выполняться приложение.

Смежные вопросы