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

В моем коде моделирования я использую boost файлы с отображением памяти для размещения больших массивов на диске.

Это работает хорошо, но я не смог найти способ обнаружить ситуацию, в которой я выделяю массив, размер которого больше, чем свободное место на диске. Например, следующий код будет успешно выполняться (при условии, что у меня меньше 8E9 байт свободного места на жестком диске):

    boost::iostreams::mapped_file_params file_params;

    file_params.path = path;
    file_params.mode = std::ios::in | std::ios::out;
    file_params.new_file_size = static_cast<size_t>(8E9); # About 10GB
    file_params.length = static_cast<size_t>(8E9);

    boost::iostreams::mapped_file result;

    result.open(file_params);

Я даже могу работать на resuld.data(), пока не запишу часть памяти, которая не выделена (из-за нехватки места на жестком диске), и тогда я получаю следующую ошибку:

 memory access violation at address: 0x7e9e2cd1e000: non-existent physical address

Есть ли способ обнаружить эту ошибку до того, как я получу загадочное memory access violation?

Я на самом деле проверил это: если файл больше доступного свободного места в разделе, код имеет нарушение доступа к памяти, если он меньше, код работает (я проверил это, изменив свободное пространство в разделе, а не редактируя код).

Возможные решения

Если я std:fill содержимым файла с нулями, я все равно получаю memory access violation, но эта ошибка находится рядом с распределением и ее легче отлаживать. Я бы предпочел, чтобы какой-то способ вызвать исключение.


person jb.    schedule 31.10.2014    source источник
comment
Для меня это не похоже на то, что у вас заканчивается дисковое пространство, но вы получаете доступ к памяти за пределами диапазона, который вы отобразили. Действительно ли 1E11 не 0x1E11?   -  person Oncaphillis    schedule 31.10.2014
comment
Это полностью связано с дисковым пространством, и я действительно получаю эту ошибку. Если я выделяю 8 ГБ на моем /tmp (размером 10 ГБ), код работает, если я записываю файл размером 2,5 ГБ в этот раздел, он взрывается с этой ошибкой. Это может быть какая-то непонятная ошибка в boost --- это может быть молчаливое усечение пространства (в этом случае я действительно получил бы доступ к памяти за пределами диапазона).   -  person jb.    schedule 31.10.2014
comment
@user Я отредактировал вопрос --- я действительно предположил, что числа не имеют значения. На самом деле это около 8 ГБ, цифры должны отражать это сейчас. Извините за недопонимание.   -  person jb.    schedule 31.10.2014
comment
структурированная обработка исключений старше, чем LINUX. Но по какой-то непонятной для меня причине он не попал в LINUX. Таким образом, найдите ОС, которая обеспечивает это, и тогда вы сможете справиться с проблемами out_of_disk_space, когда они возникнут. С другой стороны, убийца LINUX_OUT_OF_MEMORY говорит мне, что некоторые разработчики LINUX считают такие сценарии маловероятными (усмехается).   -  person    schedule 21.04.2015


Ответы (2)


Вы можете использовать fallocate или posix_fallocate, чтобы зарезервировать место для файла заранее. Таким образом, вы знаете, что никогда не будете «переусердствовать». У него есть недостаток производительности, конечно, при первоначальном создании.

По соображениям безопасности ОС, скорее всего, обнулит блоки на fallocate.

fallocate позволяет вам делать незаписанные экстенты, но при первом доступе они все равно обнуляются. В windows с этим можно бороться, SetFileValidData позволяет обойти даже это.

Обратите внимание, что Linux с O_DIRECT + fallocate() по-прежнему использует значительную часть ЦП (в отличие от Windows SetFileValidData), и хотя пропускная способность ввода-вывода обычно является узким местом, это все же может иметь заметный эффект производительности, если вы одновременно выполняете много работы ЦП.

person sehe    schedule 31.10.2014
comment
Есть ли способ сделать это, сохранив независимость от платформы? Хотя это не является строгим требованием --- на данный момент все приложение написано с использованием независимых от платформы инструментов, и его потеря будет незначительной проблемой. - person jb.; 01.11.2014
comment
Я думаю, что posix_fallocate может получить поддержку по всем направлениям. - person sehe; 01.11.2014
comment
Ну по крайней мере на всех posix системах. Возможно, я не совсем ясно выразился: было бы очень хорошо, если бы это решение работало и в Windows. - person jb.; 01.11.2014
comment
@jb. Windows реализует большую часть (все?) POSIX. Делал так много лет. Я бы проверил. - person sehe; 01.11.2014
comment
Возможно, вы правы. Windows реализует некоторые части posix. И даже если нет, я определенно смогу использовать уровень совместимости с cygwin. - person jb.; 01.11.2014

Есть ли способ обнаружить эту ошибку, прежде чем я получу критическое нарушение доступа к памяти?

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

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

person Turbo J    schedule 31.10.2014
comment
Примерно так я и делаю сейчас, но это не решит мою проблему, если я: std::fill(result.data(), result.data()+this->array_size_bytes, 0);. Я все еще получаю `` нарушение доступа к памяти``. Это нарушение гораздо проще отладить, но все же. Я бы предпочел какую-то ошибку, которую я могу перехватить, а затем вывести полезную информацию на консоль. - person jb.; 01.11.2014