Процесс Java в Mac OSX не освобождает сокет

Время от времени я сталкиваюсь со странной проблемой (на самом деле слишком часто).

Я запускаю серверное приложение, которое привязывает сокет к себе.

Но время от времени сокет не освобождается. Процесс умирает, хотя Eclipse сообщает, что Terminate не удалось, однако он правильно исчезает из «ps» и JConsole/JVisualVM. 'lsof' также больше ничего не отображает для порта. Но все же я получаю эту ошибку, когда пытаюсь снова запустить сервер на тот же порт:

Caused by: java.net.BindException: Address already in use
    at sun.nio.ch.Net.bind(Native Method)
    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:126)
    at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59)

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

Я использую MacOSX 10.7.3.

Java(TM) SE Runtime Environment (сборка 1.6.0_31-b04-415-11M3635) Java HotSpot(TM) 64-битный сервер VM (сборка 20.6-b01-415, смешанный режим)

У меня также есть Parallels, и часто проблема выглядит так, как будто она вызвана сетевым адаптером Parallels, но я не уверен, имеет ли это какое-то отношение к этой проблеме (пока я связался с их службой поддержки без какой-либо помощи).

Единственное, что помогает разрешить ситуацию, это перезагрузка OSX.

Любые идеи?

--

Это соответствующий код для открытия сокета:

channel = (ServerSocketChannel) ServerSocketChannel.open().configureBlocking(false);
 channel.socket().bind( addr, 0 );

и он закрыт

  channel.close();

Но я предполагаю, что процесс здесь зависает, а затем Eclipse его убивает.

--

netstat -an (для порта 6007):

tcp4      73      0  127.0.0.1.6007         127.0.0.1.51549        ESTABLISHED
tcp4       0      0  127.0.0.1.51549        127.0.0.1.6007         ESTABLISHED
tcp4      73      0  127.0.0.1.6007         127.0.0.1.51544        CLOSE_WAIT 
tcp4       0      0  127.0.0.1.6007         127.0.0.1.51543        CLOSE_WAIT 
tcp4       0      0  10.37.129.2.6007       *.*                    LISTEN     
tcp4       0      0  10.211.55.2.6007       *.*                    LISTEN     
tcp4       0      0  127.0.0.1.6007         *.*                    LISTEN     
tcp4       0      0  10.50.100.236.6007     *.*                    LISTEN     

--

И теперь я получаю это исключение после открытия сокета для каждого теста (вывод netstat из этой ситуации):

Caused by: java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at java.net.SocketInputStream.read(SocketInputStream.java:182)

--

Остановив процесс из eclipse, я получил «Ошибка завершения», но lsof -i TCP: 6007 ничего не отображает, и процесс больше не обнаруживается с помощью «ps». вывод netstat не изменился...

Можно ли как-то убить сокет без перезагрузки (это уже немного помогло бы)?

--

ОБНОВЛЕНИЕ 5.5.12:

Сейчас я провел тесты в отладчике Eclipse. На этот раз тесты застряли после 18 методов. Я остановил основной поток после того, как он застрял примерно на 15 минут. Это стек:

Thread [main] (Suspended)   
    FileDispatcher.preClose0(FileDescriptor) line: not available [native method]    
    SocketDispatcher.preClose(FileDescriptor) line: 41  
    ServerSocketChannelImpl.implCloseSelectableChannel() line: 208 [local variables unavailable]    
    ServerSocketChannelImpl(AbstractSelectableChannel).implCloseChannel() line: 201 
    ServerSocketChannelImpl(AbstractInterruptibleChannel).close() line: 97  
...

--

Хм, похоже, процесс ведь не убивается — и не умирает, чтобы убить -9 тоже (я заметил, что процесс 712 и, вероятно, тоже 710 — это процессы TestNG):

$ kill -9 712
$ ps xa | grep java
  700   ??  ?E     0:00.00 (java)
  712   ??  ?E     0:00.00 (java)
  797 s005  S+     0:00.00 grep java

-- Редактировать: 10.5.12:

?E в приведенном выше выводе ps означает, что процесс завершается. Я не мог найти никаких средств, чтобы полностью убить такой процесс без перезагрузки. Та же проблема была замечена с некоторыми другими приложениями. Решений не найдено:

http://www.google.com/search?q=ps+process+is+exiting+osx


person Jouni Aro    schedule 25.04.2012    source источник
comment
В своих тестах вы неоднократно привязывались и отвязывались от сокета? Если вы делаете это очень быстро, возможно, вы столкнулись с какой-то ошибкой, зависящей от времени.   -  person Marko Topolnik    schedule 25.04.2012
comment
Можете ли вы показать свой код для создания и привязки сокета, а также любые установленные вами параметры.   -  person JeremyP    schedule 25.04.2012
comment
Также запустите netstat -an сразу после того, как тест не сможет определить, находится ли сокет в состоянии TIME_WAIT.   -  person JeremyP    schedule 25.04.2012
comment
Содержится ли ваш open() в блоке try/finally? Код для закрытия вашего сокета должен быть в файле finally{}. Пожалуйста, опубликуйте больше кода, чтобы показать, как он закрывается и обрабатываются исключения.   -  person Nate    schedule 01.05.2012
comment
Нет, это не блок try-finally. Это серверный код. Сервер запускается и закрывается по запросу. Вопрос в том, почему сокет не закрывается, когда процесс умирает, что, я думаю, должно происходить всегда. А также как освободить сокет для повторного использования без перезагрузки, если это произойдет.   -  person Jouni Aro    schedule 01.05.2012
comment
Как говорили другие люди, пожалуйста, добавьте больше кода. Это поможет определить, является ли это проблемой программирования или вы столкнулись с другими проблемами, связанными с жизненным циклом сокета.   -  person Daniel H.    schedule 04.05.2012
comment
Проблема в том, что код находится в довольно большой библиотеке, и закрытие канала сокета просто закрыто - я просто не могу перетащить весь код, который связан. Но этот же код без проблем работает в Windows и Linux уже несколько лет. Теперь, когда я недавно перешел на OSX, я довольно часто видел это на своем собственном компьютере. Я также слышал странные жалобы от наших клиентов, использующих библиотеку, что их серверные приложения не всегда закрываются в OSX. Я не уверен, но я начал думать, что это, вероятно, причина и в этом.   -  person Jouni Aro    schedule 04.05.2012
comment
Я отредактировал часть кода, чтобы показать «закрытие», в котором нет ничего особенного.   -  person Jouni Aro    schedule 04.05.2012
comment
процесс, скорее всего, не завершен. к сожалению, netstat на Mac не может показать процесс владения (насколько я знаю). если процесс завершен, вы столкнулись с ошибкой в ​​macos. если вы знаете pid процесса, вы можете kill -9 его. в качестве альтернативы вы запускаете виртуальную машину в Linux и можете использовать eclipse для отладки.   -  person bestsss    schedule 05.05.2012
comment
Процесс завершается eclipse, хотя он сообщает о сбое Terminate. Он просто не освобождает сокет. Для меня это тоже звучит как ошибка в OSX. В таком случае, как я могу получить какие-то действия для этого?   -  person Jouni Aro    schedule 05.05.2012
comment
Добавлен вывод kill -9 и ps xa   -  person Jouni Aro    schedule 05.05.2012
comment
попробуйте sudo kill -9 712, при уничтожении вещей я предпочитаю убедиться, что запускаю его как root (обычно). Кстати, если процесс является зомби, вам также нужно убить родителя (вероятно, затмение)   -  person bestsss    schedule 05.05.2012
comment
опять же, если все дело закончится ошибкой в ​​macos, запустите виртуальную машину Linux под macos и отладьте приложение под linux. вы сказали, что это серверное приложение, вы будете запускать его под macos в продакшене?   -  person bestsss    schedule 05.05.2012
comment
sudo kill также не убил его ... На самом деле это код библиотеки, и серверы, созданные с его помощью, работают в Windows / Linux / OSX и, возможно, в других вариантах Unix. OSX единственная с такими проблемами.   -  person Jouni Aro    schedule 05.05.2012
comment
Вы воспроизвели проблему в системе, в которой не работает Parallels?   -  person Old Pro    schedule 10.05.2012
comment
Вопрос: Можете ли вы опубликовать дамп потока, как выглядит приложение, когда его пытается закрыть TestNG? Это всего лишь попытка заблудиться, но можете ли вы также убедиться, что любой поток, ожидающий Selector.select(), был разбужен и завершился?   -  person Sam Goldberg    schedule 10.05.2012
comment
@Sam Goldberg Этот совет, похоже, попал по правильному адресу! Сервер использовал глобальный экземпляр Selector. Он не закрывался, но тем не менее при последующих открытиях/закрытиях сервера как-то зависал. Я изменил код сервера, чтобы использовать новый селектор каждый раз, когда он создается, и теперь все тесты выполняются. Мне нужно будет немного больше изучить код (изначально не мой собственный) и выяснить, повлияет ли изменение на какие-либо другие эффекты или это правильный путь.   -  person Jouni Aro    schedule 11.05.2012
comment
@jouniaro: я столкнулся с аналогичной проблемой в Linux, где казалось, что потоки зависают в некоторых методах SocketChannel, когда другой поток ожидает Selector.select(). Подобно тому, что вы видели, этой проблемы также не было в Windows. Это похоже на реализацию селектора Unix C Library.   -  person Sam Goldberg    schedule 11.05.2012
comment
ХОРОШО. Я думал, что это было проверено на Linux, но теперь я не уверен на 100%, так ли это на самом деле. Это произошло и с обычным серверным процессом после нескольких запусков/выключений. Возможно, селектор не был закрыт должным образом, и это точная причина. В Linux модульные тесты не запускались, но и фактический серверный процесс никогда не зависал, что произошло в OSX. Может быть, там просто более вероятно, или сервер просто не был настолько разработан под Linux, что там это произошло бы.   -  person Jouni Aro    schedule 11.05.2012


Ответы (5)


попробуйте закрыть сокет с помощью http://docs.oracle.com/javase/1.4.2/docs/api/java/net/ServerSocket.html#close() после каждого теста при разборке, если вы еще этого не сделали.

person grahaminn    schedule 04.05.2012
comment
Смотрите мой новый комментарий к вопросу. Сокет должен быть закрыт объектами сервера, созданными для каждого теста, когда сервер закрыт. - person Jouni Aro; 04.05.2012
comment
Вы проверяете исключения на 'channel.close()'? - person grahaminn; 04.05.2012
comment
Да, но они были съедены. Я запустил тесты в отладчике с точкой останова, установленной в предложении catch. Выяснилось, что однажды произошла ошибка в финализации сервера, из-за которой не удалось вызвать закрытие. Однако TestNG (который я использую) остановил процесс — и сокет снова остался в зарезервированном состоянии, и мне пришлось назначить новый сокет, чтобы тесты снова могли запускаться. В Windows у меня никогда не было проблем с тем, что, несмотря на неудачные тесты, они не позволили бы использовать сокет снова. - person Jouni Aro; 04.05.2012
comment
Следующий запуск (с новым сокетом) снова застрял с SocketTimeoutException: истекло время ожидания чтения, когда клиент попытался получить доступ к сокету. И теперь все тесты истекают по той же причине. Отладчик не останавливался на предложении catch в channel.close() и не регистрировал никаких ошибок (я также добавил ведение журнала туда)... - person Jouni Aro; 04.05.2012
comment
И тот же результат для следующего запуска с новым сокетом, после 14-го метода тестирования (у меня в наборе несколько сотен) - person Jouni Aro; 04.05.2012
comment
Выяснилось, что однажды произошла ошибка в финализации сервера, из-за которой не удалось вызвать закрытие. Похоже, что закрытие должно быть вызвано в блоке «наконец», в демонтаже теста, чтобы он гарантировал вызываться после каждого теста. - person grahaminn; 05.05.2012
comment
Да можно так рассуждать. Но это не кажется актуальным, так как это произошло всего один раз. Тем не менее чтение сокета начинает истекать после выполнения нескольких тестов, хотя ошибок из-за закрытия сокета или откуда-либо еще нет. - person Jouni Aro; 05.05.2012

Здесь просто выстрел в темноту, но убедитесь, что любой поток, ожидающий Selector.select(), был разбужен и завершился.

person Sam Goldberg    schedule 14.05.2012
comment
Мне нужно будет проверить это полностью, когда я найду время. Кажется, что фактический сервер все еще иногда блокируется при закрытии, хотя тесты стали работать лучше. - person Jouni Aro; 19.05.2012
comment
Кажется, что здесь виноват Селектор, но, похоже, с ним что-то не так. У меня есть версия, которая создает новый селектор для каждого теста и закрывает его, но, тем не менее, закрытие может иногда зависать. Теперь я установил новый Oracle JDK 7u4, который первым включает поддержку Mac, и, похоже, он решил проблему, независимо от того, как используется селектор. Я хотел бы принять ваш ответ, так как вы указали правильное направление, но в конечном итоге это не помогло решить его должным образом. - person Jouni Aro; 24.05.2012
comment
@jouniaro: Спасибо за обновление. Приятно знать, что JDK 7 устранил проблему. Теперь, когда я помню, я должен также сказать, что я думаю, что проблема, которую мы видели с Selector, была хуже, когда мы использовали JRockit JDK, и зависание определенно было в части кода JNI. Так что кажется вероятным, что новый JDK может решить всю проблему. - person Sam Goldberg; 25.05.2012

Таким образом, проблема заключается в реализации Selector в версии JDK 6 для Mac. Установка нового Oracle JDK 7u4 устраняет проблему, независимо от того, как используется Selector.

person Jouni Aro    schedule 24.05.2012
comment
Я должен добавить, что я все еще иногда сталкиваюсь с той же проблемой с последней версией JDK7u21, хотя и гораздо реже, чем с JDK6. - person Jouni Aro; 26.04.2013
comment
Проблема была обнаружена и в Linux. Иногда я могу воспроизвести его (гораздо реже, чем на Java 6/OSX) на Ubuntu. Другой человек говорит, что может легко воспроизвести это на Redhat Linux. - person Jouni Aro; 08.07.2015
comment
Оказалось, что проблема в Linux немного отличается от исходной проблемы в Mac. Как-то связано с Selector, но до конца еще не раскрылось. - person Jouni Aro; 12.10.2015

У меня также есть Parallels, и часто проблема выглядит так, как будто она вызвана сетевым адаптером Parallels....

Я бы сказал, что это справедливая ставка, если эта проблема не возникает на других платформах. Что вы сделали, чтобы исключить Parallels как виновника?

person Old Pro    schedule 10.05.2012
comment
Да, хороший вопрос. Мне пока не удалось отключить сетевые интерфейсы Parallels, поскольку, если виртуальная машина приостановлена ​​или остановлена, кажется, что интерфейсы все равно остаются включенными. Мне нужно будет повторить это еще немного - почему-то у меня сложилось впечатление, что это может не повлиять на это в конце концов. Кроме того, то, что я только что добавил в редактирование, создает впечатление, что это обычная проблема OSX. - person Jouni Aro; 10.05.2012
comment
@jouniaro, неубиваемые завершающиеся процессы часто являются результатом взаимоблокировок ядра, которые возникают из-за ошибочных расширений ядра, таких как (возможно) сетевые интерфейсы Parallels. Вам нужно либо удалить Parallels, либо попытаться воспроизвести проблему на другом Mac, на котором не установлены Parallels (или Fusion). - person Old Pro; 10.05.2012
comment
Я согласен с Old Pro, вы должны протестировать Mac без параллелей, чтобы определить, имеет ли Parallels какое-то отношение к проблеме. Если это работает, кажется, проблемы на стороне параллелей. Это не так, по крайней мере, вы знаете, что проблема связана с OSX. Будет полезно, если вы сможете предоставить минимальный класс и тест для воспроизведения проблемы. - person Daniel H.; 10.05.2012
comment
Да, я постараюсь над этим поработать. К сожалению, я очень занят реальными проблемами, и это всего лишь неприятный побочный эффект, который я тоже хочу решить в какой-то момент. Не уверен, что у меня будет время протестировать его в ближайшие дни... - person Jouni Aro; 10.05.2012

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

пример очень простого останова:

public void shutDownProceedure(){
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            /* my shutdown code here */
        }
    });
}

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

Это также позволило мне увидеть журналы, которые я раньше не видел.

person Community    schedule 10.05.2012