LINUX.ORG.RU

Хранить инициализационные данные не в памяти

 


2

5

Привет!

Есть приложение для расчетов одной формулы. Для этого нужны две таблицы по несколько сотен метров каждая. Мне нужно, чтобы эти таблицы загрузились в память только когда мне это будет нужно. Массивы достаточно большие, поэтому просто написать

struct a = { { 0x23742342u, 0x23742500u, 0x23744000u ... 
нельзя - я так понял, я либо в стек не влезу, либо на старте буду жрать очень много памяти.

Есть проблема - приложение должно быть stand-alone и однофайловое. То есть хранить таблицу где-то рядом не получится.

Есть какая-нибудь возможность (желательно негеморройно-кросплатформенная, приложение для никса и шиндов) хранить в бинаре таблицу, а когда нужно - загрузить ее в память?

Почитай на тему создания вирусов и троянов. Серьезно. Очень интересно там данные прячут в бинарники.

ult
()
Ответ на: комментарий от anonymous

Может он это внутри main объявляет. Видал я таких товарищей.

anonymous
()
Ответ на: комментарий от anonymous

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

Если именно как сказали, то таки — будут. Первая же запись в сегмент данных превратит страницу с началом или концом этой таблицы в грязную страницу памяти. Потому надо константные таблицы объявлять константными, неконстантные делать c выравниванием на размер страницы и помнить, что если оно таки будет в коде, то лимиты на запуск бинаря таки сработают и может не запуститься.

vodz ★★★★★
()
Ответ на: комментарий от Immanottahere

Во-первых, вы это точно со мной спорите? Я именно это и сказал — виртуальные лимиты сработают, реальные будут поглощаться по мере использования. Ну а чего вы хотели? Это и есть данные программы. Либо храните их отдельно, либо учитывайте в размере виртуального пространства.

vodz ★★★★★
()
Ответ на: комментарий от Immanottahere

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

ilovewindows ★★★★★
()
Ответ на: комментарий от Immanottahere

Т.е. был массив, но ты добавил static... и потребление выросло. Или ты добавил массив и потребление выросло?

Где кстати объявлен массив?

anonymous
()
Ответ на: комментарий от anonymous

Массив объявлен в начале c файла.

Потребление вырастает при его объявлении.

Immanottahere
() автор топика
typedef struct {
  uint32_t m[1024 * 1024 * 25];
  //...
} data_t;

data_t data;

void init(void) {
  data = (data_t){.m = {
    //тут твоя инициализация.
  }};
}

Далее вызываешь init() когда угодно - оно проинициализирует тебе память.

rustonelove
()

Таблицу собрать в .so (или .dll), если можно порезать на несколько кусков, грузить когда нужны - dlopen. Не ?

anonymous
()

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

в своём коде организуешь инициализацию диспетчера по доступу к данным и чтеца (т.е по сути 2 функции одна создаёт и инициализирует структуру-объект, вторая с её(структуры) помощью вынимает из «мира» по нужным индексам данные)

если память во время исполнения перестаёт быть изобильной по чаще разрушаешь проинициализированое инициализатором структуро. обычный трэйдофф время-память - в следующий раз как понадобится структуру снова функцией инициализатором востановишь

твоя задача по факту одна из причин появления плюссов - упрятывания машинерии за слоем абстракции - твои два массива эдакое экстравагантное использование самодельного vector

anonymous
()

если уж совсем грубо

секция данных 2 raw-массива

в коде - функция открывает бинарь-программу на чтение seek на начало массивов и читаешь когда нуна.

anonymous
()

Храни в отдельной секции ELF-a без флага alloc. Например, у тебя твои данные в файле mydata.dat:

objcopy --add-section .mydata=mydata.dat --set-section-flags .mydata=noload,readonly main.o main_with_data.o
При линковке окончательного бинарника потом используй main_with_data.o а не main.o

При необходимости доступа к данным отмапь её в память (положение секции в файле бинарника в ELF-header есть), и загружаться оно будет по мере обращения к данным.

Для вендов тоже так можно, но без бубна это можно сделать только при помощи mingw (всё так же, как выше, только доступ к секции через PE-header, а не ELF). С ублюдочным MSVC лучше не связываться, там нужно шаманство 80lvl, а раз ты задаёшь такие вопросы, то тебе до этого левела далеко.

Stanson ★★★★★
()
Последнее исправление: Stanson (всего исправлений: 1)

Ещё вот так можно:

objcopy -I binary -O elf32-i386 --rename-section .data=noload,readonly mydata.dat mydata.o

Будет отдельный объектник, который надо будет добавить при линковке бинарника.

Но тут надо прямо указывать выходной формат (elf32-i386, или там elf64-x86-64), что не всегда удобно. В первом варианте формат будет выбран сообразно формату main.o

Stanson ★★★★★
()
Последнее исправление: Stanson (всего исправлений: 1)
Ответ на: комментарий от Stanson

А где можно почитать про все это? Про линковку, флаги, ELF-файлы и прочее? Есть какая-то книжка может или официальная дока?

Kronick
()
Ответ на: комментарий от Kronick

Ну man и info на binutils, если хоть немного в курсе что к чему, если совсем ни в зуб ногой - то в гугле типа ELF file format поискать, а потом уже man и info.

Stanson ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.