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

Вот код:

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

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

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

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

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

3
Sachin Verma 4 Май 2016 в 14:06

2 ответа

Лучший ответ

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

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

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

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

writeObject0 
writeOrdinaryObject
writeSerialData
defaultWriteFields
writeObject0
etcetera

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

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

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

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

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

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

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

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

10
Stephen C 11 Авг 2017 в 07:53

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

Есть конструктор, определяющий размер стека для нового потока. Все потоки, которые не используют этот специальный конструктор, получат размер стека по умолчанию, указанный в параметре JVM (и это будет охватывать все потоки, если вы не создадите их самостоятельно).

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

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

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

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

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

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

2
Community 20 Июн 2020 в 09:12