Страница 1 из 1

Что должен делать плагин при получении Out of memory?

Добавлено: Пт ноя 15, 2019 17:58
remittor
Ни в одном плагине для TotalCmd я не нашёл обработку ошибки Out of Memory.

Сейчас пишу wcx-плагин, в котором все места с выделением дин. памяти имеют проверки. И в случае возникновения оной ошибки управление через ret дойдёт до TotalCmd.

Но честно говоря, в этой ситуации просто хочется вызвать RaiseException и забыть.

Так может так и стоит делать?
В этом случае TotalCmd завершит работу с ошибкой.

Добавлено: Сб ноя 16, 2019 02:08
CaptainFlint
Сознательно грохать Тотал при возникновении проблемы в плагине — это, конечно, сильно. Лично я бы такой плагин первым делом снёс.

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

Добавлено: Сб ноя 16, 2019 11:43
remittor
CaptainFlint писал(а):Сознательно грохать Тотал при возникновении проблемы в плагине — это, конечно, сильно.
Во всех плагинах, что я видел, не перехватывается исключение EOutOfMemory/bad_alloc, что ведёт к завершению работы процесса с выдачей ошибки.
Да там вообще нет никакой обработки исключений.
Если в плагине юзается System.String/std::string , то без обработки исключений есть шанс словить EOutOfMemory от плагина.
CaptainFlint писал(а):Лично я бы такой плагин первым делом снёс.
В плагинах DEB И RPM используется System.String и при этом вообще нет отлова исключений. Поэтому можно смело сносить эти плагины, т.к. они могут сгенерить исключение EOutOfMemory.
К тому же в плагине DEB нет проверки результата GetMem, что тоже может привести к "падению" TotalCmd.

В плагине Office2007wlx используется оператор new() , но перехвата исключения bad_alloc нету. Вообще нету try/catch!!!

В плагине NTLinks проверяется результат malloc. А вот результат realloc (вызывается внутри какого то объекта) не проверяется совсем никак.
CaptainFlint писал(а):В API не зря предусмотрены различные коды ошибок в качестве возвращаемых значений. Если возникает нештатная ситуация, считается, что разработчик плагина должен её обработать в своём коде и вернуть ошибку Тоталу, чтобы тот понял, что операция не удалась.
Всегда так и делаю. Вопрос был о другом. Сейчас сам TotalCmd никак не обрабатывает EOutOfMemory/bad_alloc. Поэтому при реальной нехватке памяти вы управление возвратите в TotalCmd, но он сам при этом "свалится" при первой работе с System.String и т.п.

Поэтому и встаёт вопрос: а нафига заморачиваться с ловлей EOutOfMemory/bad_alloc (для крошечных блоков памяти), коли сам TotalCmd не ловит эти исключения?

Добавлено: Сб ноя 16, 2019 13:23
CaptainFlint
Ну, доступные ресурсы — это такая вещь… Сейчас он свалился от нехватки памяти, а следующий запрос на выделение пройдёт успешно из-за того, что какая-то жирная программа освободила блок или вовсе завершила работу. Кроме того, крошечные блоки могут превратиться в некрошечные, если их размер зависит от внешних факторов. Например, пользователь сдуру открыл десятигигабайтный файл, плагин начал его читать в память (крошечными блоками), исчерпал объём, получил исключение и свалился. Грохать весь Тотал в такой ситуации неразумно, ибо ресурсов в системе для нормальной работы вполне достаточно (если, конечно, плагин освободит всю эту сожранную им память).

Добавлено: Сб ноя 16, 2019 14:31
remittor
CaptainFlint писал(а):Ну, доступные ресурсы — это такая вещь… Сейчас он свалился от нехватки памяти, а следующий запрос на выделение пройдёт успешно из-за того, что какая-то жирная программа освободила блок или вовсе завершила работу.
Всё верно. Для этого все и должны использовать RAII + try/catch.
Но в описанной вами ситуации сам TotalCmd может в классе System.String или GetMem сгенерировать EOutOfMemory.
Получается, что TotalCmd можно болт забивать на ловлю исключений, а нам нельзя?
CaptainFlint писал(а):Кроме того, крошечные блоки могут превратиться в некрошечные, если их размер зависит от внешних факторов. Например, пользователь сдуру открыл десятигигабайтный файл, плагин начал его читать в память (крошечными блоками), исчерпал объём, получил исключение и свалился.
Зачем весь десятигигабайтный файл читать целиком в память?
CaptainFlint писал(а):Грохать весь Тотал в такой ситуации неразумно, ибо ресурсов в системе для нормальной работы вполне достаточно.
Так я не об этой сутуации написал.
Я написал о ситуации, когда в динамическую строку нужно сохранить путь к файлу или другую мелкую информацию.

Что должен делать плагин, когда в конструкторе какого либо класса произошёл EOutOfMemory при инициализации динамической строки System.String/std::string ?
Из конструктора код ошибки не возвратить. Нужно обрамлять в try/catch весь код.

Добавлено: Вс ноя 17, 2019 14:52
CaptainFlint
remittor писал(а):Получается, что TotalCmd можно болт забивать на ловлю исключений, а нам нельзя?
Я не сужу, кому можно, а кому нельзя. Я просто говорю, что ловить и обрабатывать исключения — это хороший тон, и что такими разработками пользоваться куда приятнее. Если в Тотале этого нет, это, конечно, плохо. Только стоит ли на этом основании делать ситуацию ещё хуже, увеличивая чисто точек отказа, приводящих к краху с потерей данных?
remittor писал(а):Зачем весь десятигигабайтный файл читать целиком в память?
Да мало ли ситуаций… Скажем, плагин просмотра картинок, который не ожидал, что его вызовут на гигапиксельную Hubble eXtreme Deep Field. Или просмотр кода с подсветкой синтаксиса, где некоторые грамматики требуют полного парсинга. Ну или бывает, что сам файл держать в памяти необязательно, можно обрабатывать потоковым алгоритмом, но результаты парсинга в итоге занимают столько же, а то и больше места (как какой-нибудь JSON, XML).
remittor писал(а):Что должен делать плагин, когда в конструкторе какого либо класса произошёл EOutOfMemory при инициализации динамической строки System.String/std::string ?
Из конструктора код ошибки не возвратить. Нужно обрамлять в try/catch весь код.
Учитывая, что API не является объектно-ориентированным, на верхнем уровне всё равно будет реализация какого-нибудь ListLoad(). Я не вижу, в чём проблема обернуть содержимое этого метода в один большой try/catch. Сложнее, конечно, разобраться с освобождением ресурсов, если исключение всё же произошло, но тут уже от конкретного кода всё зависит.