Как проектировать: избегать утечки ресурсов при случайном доступе к файлам - PullRequest
4 голосов
/ 24 марта 2012

У меня есть клиент-серверное приложение, где клиентское приложение будет открывать файлы.Эти файлы разбиваются на куски и отправляются на сервер.

Клиент не только отправляет куски файлов, но и отправляет другие данные.Каждое сообщение (data или filechunk) имеет уровень приоритета.

Все сообщения буферизуются и записываются в поток TCP в соответствии с их приоритетом.В настоящее время потоки ввода и вывода закрываются с обеих сторон (клиент / сервер) всякий раз, когда файл полностью отправляется или принимается.Это означает, что потоки остаются открытыми столько времени, сколько требуется для отправки файлов.

Разрешено сбой соединения TCP, так как он будет переподключен, и отправка сообщения будет возобновлена, поэтому потокив какой-то момент будет закрыто.

НО, если и когда JVM будет убита, например, потоки не будут очищены.

Моя первая мысль о решенииэто было для добавления кода очистки в финализаторы, но я понимаю, что они могут не работать, когда JVM будет убита (или если вызывается System.exit).

Моя вторая мысль - переписать часть приложения иИспользуйте потоки только столько времени, сколько нужно для чтения / записи одного фрагмента.Поэтому я бы заканчивал тем, что открывал / закрывал файлы столько раз, сколько есть фрагментов.Преимущество этого метода состоит в том, что он позволяет мне использовать конструкции try-catch-finally, но у меня есть чувство, что я открываю и закрываю файлы, что часто подразумевает значительные накладные расходы.

Так как же это сделать?очистить ресурсы, когда проект не учитывает блоки finally {} ?Или такого дизайна следует избегать, может быть, так, как я описал?

Меня также беспокоит возможность открытия столько файлов, сколько имеется приоритетов (которые в теории не ограничены).

Большинство файлов обычно имеют размер в несколько килобайт, но в некоторых случаях они могут достигать нескольких ГБ.

Заранее благодарен за ваш ввод.

РЕДАКТИРОВАТЬ: Добавлено изображение

File transfer as it is

Ответы [ 2 ]

2 голосов
/ 24 марта 2012

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

Хотя это общая проблема, в вашем конкретном случае я считаю, чтоне о чем беспокоиться.Вы открываете свои файлы только для чтения, поэтому нет постоянного состояния, которое могло бы сломать ваше приложение (как я понимаю, другая сторона TCP-соединения может корректно обрабатывать разъединения).Открываемый файл является своего рода состоянием, которое является внутренним для приложения.Если приложение убито, операционная система позаботится об очистке всех блокировок или любых структур данных, которые оно может использовать для внутренних операций с этим файлом.Это означает, что в ядре ОС не останется «мусора», и хотя это не изящный и не рекомендуемый способ очистки, он просто работает (конечно, используйте его только для экстренных случаев, а не как обычный способ).обработки вещей).Уничтожение вашего приложения автоматически закроет открытые файлы и не должно приводить файлы в несогласованное состояние.

Конечно, если приложение убито, оно не завершит никаких операций, которые оно выполняло.Это может привести к несовместимому состоянию уровня приложения или другим проблемам с некоторыми типами логики приложения, но все равно не может повредить любые структуры уровня ОС (при условии, что ОС не глючит).Вы можете потерять данные или нарушить состояние вашего приложения, но вы не сможете разбить файловую систему или данные в ядре.

Итак, вы можете столкнуться с проблемами, если убьете приложение, в котором у вас есть транзакцияоперация в стиле (та, которую вы хотите либо полностью выполнить, либо не выполнять вообще, но никакое промежуточное состояние никогда не должно становиться видимым для внешнего мира).Например, если у вас есть файл, и вам необходимо заменить его на более новую версию.Если вы сначала обрежете старый файл, а затем напишите в него новое содержимое (что является очевидным способом сделать это), если ваше приложение будет убито после усечения файла, но перед записью нового содержимого, у вас возникнут проблемы.Однако для того, чтобы спровоцировать такие риски, вам нужно изменчивое состояние, то есть что-то писать.Если вы только читаете материал, вы почти наверняка в безопасности.

Если вы столкнетесь с таким случаем, вы можете выбрать несколько путей.Один пытается сделать приложение пуленепробиваемым и гарантировать, что оно всегда хорошо очищается.На практике это очень сложно.Вы можете добавить перехватчики завершения работы к Java-приложению, которое будет выполняться при закрытии приложения, но оно работает только для контролируемого завершения работы (как обычный kill (SIGTERM) в Linux).Но это не защитит вас от принудительного уничтожения приложения администратором (kill -9 в Linux), OOM-killer (также Linux) и т. Д. Конечно, другие операционные системы имеют эквиваленты этих ситуаций или других случаев.где приложение закрыто таким образом, что оно не может контролировать.Если вы не пишете приложение реального времени, работающее в контролируемой аппаратной и программной среде, практически невозможно предотвратить все способы принудительного завершения работы приложения и запрета на выполнение процедур очистки.

Таким образом, разумным компромиссом часто является принятие в приложении только простых мер предосторожности (например, отключений), но следует помнить, что вы не можете предотвратить все и, следовательно, сделать ручную очистку возможной и простой.Например, решение для случая перезаписи файла состояло бы в том, чтобы разделить операцию на первое перемещение старого файла на новое имя для сохранения в качестве резервной копии (эта операция обычно атомарна на уровне ОС и, следовательно, безопасна), затем записатьновое содержимое файла со старым именем, а затем после проверки правильности записи нового файла, удалив резервную копию.Таким образом, если приложение уничтожается между операциями, существует простая процедура очистки: перемещение файла резервной копии к исходному имени и, таким образом, возврат к более старому, но согласованному состоянию.Это может быть выполнено вручную (но должно быть задокументировано), или вы можете добавить сценарий очистки или специальную команду «очистки» в ваше приложение, чтобы сделать эту операцию простой, видимой и устранить возможность человеческой ошибки во время процедуры.Предполагая, что ваше приложение убивают очень редко, это обычно более эффективно, чем тратить много времени на то, чтобы сделать приложение пуленепробиваемым только для того, чтобы понять, что это на самом деле невозможно.Охватить сбой часто лучше, чем пытаться предотвратить его (не только в программировании).

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

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

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

Посмотрите на java.lang.Runtime.addShutdownHook(). Я бы попробовал добавить хук, который закрывает все открытые потоки, список которых вы должны поддерживать для этого случая. Однако учтите это:

В редких случаях виртуальная машина может прерваться, то есть прекратить работу без выключения. Это происходит, когда виртуальная машина завершается извне, например, с помощью сигнала SIGKILL в Unix или вызова TerminateProcess в Microsoft Windows. Виртуальная машина также может прервать работу, если собственный метод не работает, например, из-за повреждения внутренних структур данных или попытки доступа к несуществующей памяти. Если виртуальная машина прерывается, то нельзя дать никаких гарантий относительно того, будут ли запущены какие-либо перехватчики завершения работы.

...