На контестах довольно часто встречаются задачи, требующие применения глубокой рекурсии. Обычно это задачи на графы с большими ограничениями, решение которых использует поиск в глубину. А глубокая рекурсия требует большого размера доступного стека, часто несколько мегабайт.
В таких языках программирования, как C++ или Pascal/Delphi, размер стека можно установить с помощью директив компилятору. Однако в Java это сделать нельзя. Размер стека, выделяемый потоку Java по умолчанию, весьма мал, на 32-битной Windows всего 320kb. Самым простым способом установить размер стека для потока Java является использование ключа командой строки -Xss для JVM. Вот тут-то и начинаются проблемы.
Во-первых, об этом нужно знать) Практика показывает, что плохое представление о Java имеют не только низкоуровневые соревнования (Западно-Сибирский четвертьфинал ACM ICPC), но и вполне приличные архивы задач, например, TJU. В результате приходится писать либо нерекурсивный dfs, что не всегда тривиально и всегда лениво, либо писать/переписывать на C++, что просто печально.
Во-вторых, недостатки имеет сам ключ -Xss. При его использовании указанный размер стека выделяется всем потоками приложения. Для простого однопоточного приложения это не страшно, однако это может создать проблемы для тестирующей системы, если в ней одновременно могут выполняться много потоков Java.
Кроме того, возникает вопрос неучтенной памяти - если тестирующая выставляет ограничение по памяти с помощью ключа -Xmx, то программа, вообще говоря, может использовать больше памяти - добавляется стек. Поэтому контроль проверки на Memory Limit Exceeded с помощью перехватывания OutOfMemoryError будет работать не совсем корректно.
Стоит, однако, сказать, что эти недостатки вполне себе преспокойно игнорируются. Стандартная командная строка запуска jvm вида
java -Xmx<?>М -Xss<?>M <class name>
используется на NEERC, что указано в раздаваемых перед контестом правилах (хотя об этом почему-то ничего нет на официальном сайте), на Timus и на петрозаводских сборах. Есть также подозрения, что что-то подобное используется на финале ACM ICPC, хотя опять же, только по словам на Q&A Session.
В-третьих, до Java 1.6 эта установка использовалась только во вновь созданных потоках, в то время как main thread использовал стандартный для ОС размер стека. Поэтому приходилось писать в main-методе что-то вроде
Не увидев в описании компиляторов нужных параметров, я поспешил написать коммент. Какого же было моё удивление, когда MikeMirzayanov ответил, что "Правильно запускать новый Thread с нужным размером стека и в нем осуществлять решение задачи". Я всю жизнь думал, что этого сделать нельзя) Но, посмотрев JavaDoc (почему я не сделал этого раньше?), я нашел такой вот замечательный конструктор у Thread:
Может быть, у вас возникали какие-то еще проблемы со стеком или вы знаете другие способы его установить? Пишите в комментах)
В таких языках программирования, как C++ или Pascal/Delphi, размер стека можно установить с помощью директив компилятору. Однако в Java это сделать нельзя. Размер стека, выделяемый потоку Java по умолчанию, весьма мал, на 32-битной Windows всего 320kb. Самым простым способом установить размер стека для потока Java является использование ключа командой строки -Xss для JVM. Вот тут-то и начинаются проблемы.
Во-первых, об этом нужно знать) Практика показывает, что плохое представление о Java имеют не только низкоуровневые соревнования (Западно-Сибирский четвертьфинал ACM ICPC), но и вполне приличные архивы задач, например, TJU. В результате приходится писать либо нерекурсивный dfs, что не всегда тривиально и всегда лениво, либо писать/переписывать на C++, что просто печально.
Во-вторых, недостатки имеет сам ключ -Xss. При его использовании указанный размер стека выделяется всем потоками приложения. Для простого однопоточного приложения это не страшно, однако это может создать проблемы для тестирующей системы, если в ней одновременно могут выполняться много потоков Java.
Кроме того, возникает вопрос неучтенной памяти - если тестирующая выставляет ограничение по памяти с помощью ключа -Xmx, то программа, вообще говоря, может использовать больше памяти - добавляется стек. Поэтому контроль проверки на Memory Limit Exceeded с помощью перехватывания OutOfMemoryError будет работать не совсем корректно.
Стоит, однако, сказать, что эти недостатки вполне себе преспокойно игнорируются. Стандартная командная строка запуска jvm вида
java -Xmx<?>М -Xss<?>M <class name>
используется на NEERC, что указано в раздаваемых перед контестом правилах (хотя об этом почему-то ничего нет на официальном сайте), на Timus и на петрозаводских сборах. Есть также подозрения, что что-то подобное используется на финале ACM ICPC, хотя опять же, только по словам на Q&A Session.
В-третьих, до Java 1.6 эта установка использовалась только во вновь созданных потоках, в то время как main thread использовал стандартный для ОС размер стека. Поэтому приходилось писать в main-методе что-то вроде
new Thread() { public void run() { new Main().run(); } }.start();С появлением 1.6 это стало не нужно, и я уже начал забывать о всех беспокойствах, связанных со стеком. Но тут появился Codeforces.
Не увидев в описании компиляторов нужных параметров, я поспешил написать коммент. Какого же было моё удивление, когда MikeMirzayanov ответил, что "Правильно запускать новый Thread с нужным размером стека и в нем осуществлять решение задачи". Я всю жизнь думал, что этого сделать нельзя) Но, посмотрев JavaDoc (почему я не сделал этого раньше?), я нашел такой вот замечательный конструктор у Thread:
public Thread(ThreadGroup group,Правда, в том же JavaDoc несколько раз было написано о том, что как будет использоваться параметр stackSize и будет ли использоваться вообще, зависит от системы. Тем не менее, проверка показала, что стек действительно выставляется, и не только на Codeforces, но и на TJU. В результате приходим к такому прекрасному оператору в main:
Runnable target,
String name,
long stackSize).
new Thread(null, new Runnable() {который устанавливает размер стека в 8 МБ для потока "1".
public void run() {
new Main().run();
}
}, "1", 1 << 23).start();
Может быть, у вас возникали какие-то еще проблемы со стеком или вы знаете другие способы его установить? Пишите в комментах)
Хочу посмотреть как ты сделаешь это легко для, допустим, поиска мостов или топологической сортировки.
Дело в том, что Java -- это не просто язык программирования, а движение, которое верит, что нашло панацею от всего.
Оно считает, что проблемы, возникающие при работе с другими языками, имеют причиной эти самые языки, а проблемы при работе на их любимом языке происходят по причине кого-то еще: пользователей программы, разработчиков ОС, на которой эта программа работает, жюри олимпиад и т.д.
Перед каким-то из полуфиналов я проверял все это под виндой, и там параметр глубины стека игнорировался. Когда мы на финале - а там линукс - не были уверены в том, дадут ли нам стек с помощью ключей, мы попробовали использовать этот конструктор, и там он заработал. Может быть, сейчас и с виндой изменилась ситуация, я не слежу.
Dude thanks a lot . I used this in getting AC in a problem involving Kosaraju's algorithm
Codeforces doesn't create a lot of threads. So why do you need to reduce stack size?
Actually this is really useful if you need to do dfs . Without increasing the stack size I wouldn't have got AC in this problem https://www.hackerearth.com/problem/algorithm/a-walk-to-remember-qualifier2/
Will you please provide a example program using Runnable interface. It will be a great help.
This is how I do every problem that involves deep recursion.