#c #linux #mmap #ace
#c #linux #mmap #туз
Вопрос:
Контекст: я использую файл с отображением памяти в своем коде, созданном с помощью ACE_Mem_Map. Наблюдается, что файл с отображением памяти занимает больше места на диске, чем ожидалось.
Сценарий: у меня есть структура, содержащая массив символов размером 15 КБ. Я создал файл карты памяти для массива этой структуры с размером файла ~ 2 ГБ.
- Если я попытаюсь получить доступ к нескольким байтам массива символов (скажем, 256), то потребляемый размер файла будет показан как 521 МБ, но фактическое использование диска, показанное файловой системой (с использованием df -h), составляет более 3 ГБ.
- Если я получаю доступ ко всем байтам памяти, то размер файла и использование диска отображаются как 2 ГБ.
Среда: ОС: Oracle Linux 7.3 Версия ядра: 3.10.0 / 4.1.12
Код:
#include<ace/Mem_Map.h>
#include <stdio.h>
#define TEST_BUFF_SIZE 15*1024
typedef struct _test_struct_ {
char test[TEST_BUFF_SIZE];
_test_struct_() {
reset();
}
void reset() {
/* Issue replicating */
memset(test, '', 256);
/* Issue not replicating */
memset(test, '', TEST_BUFF_SIZE);
}
}TestStruct_t;
int main(int argc, char *argv[]) {
if(3 != argc) {
printf("Usage: %s <num of blocks> <filename>n",
argv[0]);
return -1;
}
ACE_Mem_Map map_buf_;
size_t num_of_blocks = strtoull(argv[1], NULL, 10);
size_t MAX_SIZE = num_of_blocks*sizeof(TestStruct_t);
char* mmap_file_name = argv[2];
printf("num_of_blocks[%llu], sizeof(TestStruct_t)[%llu], MAX_SIZE[%llu], mmap_file_name[%s]n",
num_of_blocks,
sizeof(TestStruct_t),
MAX_SIZE,
mmap_file_name);
TestStruct_t *base_addr_;
ACE_HANDLE fp_ = ACE_OS::open(mmap_file_name,O_RDWR|O_CREAT,
ACE_DEFAULT_OPEN_PERMS,0);
if (fp_ == ACE_INVALID_HANDLE)
{
printf("Error opening filen");
return -1;
}
map_buf_.map(fp_,MAX_SIZE,PROT_WRITE,MAP_SHARED);
base_addr_ = (TestStruct_t*)map_buf_.addr();
if (base_addr_ == MAP_FAILED)
{
printf("Map init failuren");
ACE_OS::close(fp_);
return -1;
}
printf("map_buf_ size[%llu]n",
map_buf_.size());
for(size_t i = 0; i < num_of_blocks; i ) {
base_addr_[i].reset();
}
return 0;
}
Кто-нибудь может объяснить, почему происходит сценарий 1??
Примечание: В сценарии 1, если я создам копию сгенерированного файла mmap, а затем удалю эту копию, то дополнительные 2,5 ГБ дискового пространства будут освобождены. Не знаю причины
Комментарии:
1. Структуры C не могут иметь функций-членов.
2. @JohnBollinger, проблема повторяется, даже если я удаляю функцию-член
3. Даже без функций-членов дело в том, что это не вопрос C. ACE — это инструментарий C , и другие аспекты представленного кода также специфичны для C . Действительно, поскольку программа использует ACE для сопоставления файла, в отличие
mmap
от прямого вызова, вопрос в его нынешнем виде специфичен для ACE.4. Когда вы говорите о фактическом «размере файла», как вы это измеряете?
ls
?5. Я использую команды du и stat для проверки размера файла
Ответ №1:
Я «обновил» вашу программу почти до C и минус любой ACE и получил это:
$ ./a.out 32 fred
num_of_blocks[32], sizeof(TestStruct_t)[15360], MAX_SIZE[491520], mmap_file_name[fred]
Bus error: 10
Что в значительной степени ожидаемо. Mmap не увеличивает размер отображаемого файла, поэтому при попытке сослаться на незаполненную часть генерируется ошибка адреса.
Итак, ответ заключается в том, что независимо от того, что делает ACE.map , он, вероятно, вызывает что-то вроде ftruncate(2)
расширения файла до размера, который вы указываете в качестве параметра. @John Bollinger намекает на это, спрашивая how are you measuring that
: ls или du . Вы должны использовать последнее.
Во всяком случае, почти версия C:
#include <sys/mman.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#define TEST_BUFF_SIZE 15*1024
typedef struct _test_struct_ {
char test[TEST_BUFF_SIZE];
_test_struct_() {
reset();
}
void reset() {
/* Issue replicating */
memset(test, '', 256);
/* Issue not replicating */
memset(test, '', TEST_BUFF_SIZE);
}
}TestStruct_t;
int main(int argc, char *argv[]) {
if(argc < 3) {
printf("Usage: %s <num of blocks> <filename>n",
argv[0]);
return 1;
}
void *buf;
size_t num_of_blocks = strtoull(argv[1], NULL, 10);
size_t MAX_SIZE = num_of_blocks*sizeof(TestStruct_t);
char* mmap_file_name = argv[2];
printf("num_of_blocks[%zu], sizeof(TestStruct_t)[%zu], MAX_SIZE[%zu], mmap_file_name[%s]n",
num_of_blocks,
sizeof(TestStruct_t),
MAX_SIZE,
mmap_file_name);
int fp = open(mmap_file_name,O_RDWR|O_CREAT,0666);
if (fp == -1)
{
perror("Error opening file");
return 1;
}
/*SOMETHING CLEVER*/
switch (argc) {
case 3:
break;
case 4:
if (ftruncate(fp, MAX_SIZE) != 0) {
perror("ftruncate");
return 1;
}
break;
case 5:
if (lseek(fp, MAX_SIZE-1, SEEK_SET) != MAX_SIZE-1 ||
write(fp, "", 1) != 1) {
perror("seek,write");
return 1;
}
}
void *b = mmap(0, MAX_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fp, 0);
if (b == MAP_FAILED)
{
perror("Map init failure");
return 1;
}
TestStruct_t *base_addr = (TestStruct_t *)b;
for(size_t i = 0; i < num_of_blocks; i ) {
base_addr[i].reset();
}
return 0;
}
SOMETHING CLEVER
Бит позволяет вам либо работать с пустым файлом (argc == 3), увеличивать его с помощью ftruncate (argc == 4), либо увеличивать его с помощью lseek amp;amp; write (argc == 5).
В системах UNIX-y ftruncate может резервировать или не резервировать место для вашего файла; удлиненный файл без зарезервированного места называется sparce . Почти повсеместно lseek amp;amp; write создаст разреженный файл, если только ваша система этого не поддерживает.
Файл sparce будет выделять фактические блоки диска по мере записи в него, однако, если он завершится неудачей, он выдаст сигнал, тогда как предварительно выделенный — нет. Ваш цикл внизу проходит весь экстент, поэтому файл всегда будет увеличиваться; сократите этот цикл, и вы увидите, влияют ли параметры на вашу систему.
Комментарии:
1. В моем случае создается разреженный файл. Проблема в том, что количество дисковых блоков, выделенных для файла, не соответствует количеству дисковых блоков, потребляемых из файловой системы. Предположим, максимальный размер, заданный файлу, составляет 2 ГБ. Файл занял 521 МБ дискового пространства, как показано в выводе du -sh и stat. Но, если я вижу дисковое пространство на fs с использованием df -h, то это показывает, что потребляется ~ 3 ГБ, что намного больше, чем назначенные 2 ГБ. В чем может быть причина этого? Примечание: проблема воспроизводима и в коде, которым вы поделились, а также после строки комментария
memset(test, '', TEST_BUFF_SIZE);
и argc = 4 или 52. Умножьте РАЗМЕР ТЕСТА __BUFF_ на 10 и разделите свой arg1 на 10; Я думаю, что размер выделения вашей файловой системы — это проблема. Извините за другое, мой ubuntu 20 этого не делает.
3. Я использую файловую систему XFS. Можете ли вы поделиться, какую файловую систему вы используете??
4. xfs4 в ubuntu 20. У меня была другая мысль; возможно ли, что ваш linux создает огромные страницы? Здесь есть некоторая документация: oracle-base.com/articles/linux /… , обратите внимание на то, что нужно форсировать огромные страницы.