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

Только для тех, кто пишет плагины под Total Commander. Обмен опытом, решение проблем.

Модераторы: Avada, CaptainFlint, Nik, d-view, Моторокер

Ответить
remittor
Сообщения: 19
Зарегистрирован: Пн окт 21, 2019 14:48
Откуда: Russia

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

Сообщение remittor »

Ни в одном плагине для TotalCmd я не нашёл обработку ошибки Out of Memory.

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

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

Так может так и стоит делать?
В этом случае TotalCmd завершит работу с ошибкой.
Аватара пользователя
CaptainFlint
Сообщения: 6239
Зарегистрирован: Вт дек 14, 2004 22:34
Контактная информация:

Сообщение CaptainFlint »

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

В API не зря предусмотрены различные коды ошибок в качестве возвращаемых значений. Если возникает нештатная ситуация, считается, что разработчик плагина должен её обработать в своём коде и вернуть ошибку Тоталу, чтобы тот понял, что операция не удалась. И, кстати, нужно не забывать при этом освобождать ресурсы, чтобы файлы не оставались заблокированными, а память не утекала.
Почему же, ё-моё, ты нигде не пишешь "ё"?
remittor
Сообщения: 19
Зарегистрирован: Пн окт 21, 2019 14:48
Откуда: Russia

Сообщение 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 не ловит эти исключения?
Аватара пользователя
CaptainFlint
Сообщения: 6239
Зарегистрирован: Вт дек 14, 2004 22:34
Контактная информация:

Сообщение CaptainFlint »

Ну, доступные ресурсы — это такая вещь… Сейчас он свалился от нехватки памяти, а следующий запрос на выделение пройдёт успешно из-за того, что какая-то жирная программа освободила блок или вовсе завершила работу. Кроме того, крошечные блоки могут превратиться в некрошечные, если их размер зависит от внешних факторов. Например, пользователь сдуру открыл десятигигабайтный файл, плагин начал его читать в память (крошечными блоками), исчерпал объём, получил исключение и свалился. Грохать весь Тотал в такой ситуации неразумно, ибо ресурсов в системе для нормальной работы вполне достаточно (если, конечно, плагин освободит всю эту сожранную им память).
Почему же, ё-моё, ты нигде не пишешь "ё"?
remittor
Сообщения: 19
Зарегистрирован: Пн окт 21, 2019 14:48
Откуда: Russia

Сообщение remittor »

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

Что должен делать плагин, когда в конструкторе какого либо класса произошёл EOutOfMemory при инициализации динамической строки System.String/std::string ?
Из конструктора код ошибки не возвратить. Нужно обрамлять в try/catch весь код.
Аватара пользователя
CaptainFlint
Сообщения: 6239
Зарегистрирован: Вт дек 14, 2004 22:34
Контактная информация:

Сообщение CaptainFlint »

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