Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.14.86] |
|
Сообщ.
#1
,
|
|
|
Всем привет!
Сразу хочу сказать - мой вопрос не практический, а чисто академический. Заранее прошу прощения за некоторую гиперболизацию в своих высказываниях, бикоз настроение хорошее. Понедельник, честно сказать, гуано полное. Но я всё порешал на высшем уровне. Я - кросава, и теперь с самому вопросу... Под такое настроение я решил выяснить, а могу ли я в качестве поля класса использовать массив размером в один зетабайт? Как говорится "чего уж мелочиться". Ну да, я тут немного перегнул. Поговорил с ChatGPT4, он мне выдал такую инфу: Цитата В 64-разрядной системе теоретически максимальный объем адресуемой памяти составляет 16 эксабайт (16 ЭБ), что эквивалентно 264 байт. Однако на практике существуют ограничения, которые могут уменьшить этот объем: Но вот на второй мой вопрос к ChatGPT4, а-ля, "А в Стандартах С/С++ есть какие либо ограничения или указания по максимально-допустимым размерам объектов?" я ответ получил, типа "такого нет". Собственно вопросов несколько 1) "Граничные условия" - вестчь важная, она должна быть как-то регламентирована? Если да - то где и как? 2) А если "не", то как "правильно быть"? |
Сообщ.
#2
,
|
|
|
Прочитал на cplusplsu.com про массивы и там ничего не сказано про тип индексов для элементов. Тогда нет ограничения для размеров массивов (хоть вся доступная память). Главное, чтобы ОС смогла для этого объекта найти достаточно свободных страниц памяти и они все разом влезли в RAM (т.к. объект будет загружаться полностью перед доступом).
И еще одна догадка. Как тогда работают сейчас нейросети (тот же ChatGPT). Это же по сути массивы на Гб, если не на Тб значений. |
Сообщ.
#3
,
|
|
|
macomics, вся фишка в том, что всё в С/C++ должно и обязано соответствовать Стандартам. Это аксиома. Любой шаг вправо или влево - это ересь. Вот поэтому я и спрашиваю именно за стандарты в первую очередь.
Цитата macomics @ И еще одна догадка. Как тогда работают сейчас нейросети (тот же ChatGPT). Это же по сути массивы на Гб, если не на Тб значений. Прочитай про mmap. Навскидку не скажу, но на 100% помню, что в Уиндофс есть схожий по функционалу механизм. |
Сообщ.
#4
,
|
|
|
Цитата Majestio @ Прочитай про mmap. Навскидку не скажу, но на 100% помню, что в Уиндофс есть схожий по функционалу механизм. Это просто WinAPI CreateFileMapping. Он же есть и в Linux Прикреплённая картинка
Добавлено Про 32-битный режим я могу сказать точно. На С можно было объявить массив размером в 4Гб (максимальный доступный объем адресов). А вот для 64-битных надо искать, но по идее ограничения тоже нету. |
Сообщ.
#5
,
|
|
|
Ну да, я наверное про это и говорил. Просто в WinAPI я мало-мало путаюсь. Судя по докам, если вызов неуспешный - возвращается NULL. Законный вопрос - а как узнать сколько я могу резервировать памяти так, чтобы эта функция отработала правильно?
|
Сообщ.
#6
,
|
|
|
https://learn.microsoft.com/ru-ru/windows/w...ocessmemoryinfo
еще это https://learn.microsoft.com/en-us/windows/w...balmemorystatus Добавлено Кстати замечу. В 32-битном режиме физическая адресация (с PAE) возможна до 64 Гб (36 бит), но адресное пространство физически ограничено 32-битами (4 Гб) и как раз этим и был ограничен максимально возможный размер массива (4 Гб). |
Сообщ.
#7
,
|
|
|
https://en.cppreference.com/w/c/types/size_t
Цитата size_t can store the maximum size of a theoretically possible object of any type (including array). size_t is commonly used for array indexing and loop counting. Programs that use other types, such as unsigned int, for array indexing may fail on, e.g. 64-bit systems when the index exceeds UINT_MAX or if it relies on 32-bit modular arithmetic. Соответственно, объект не может быть больше максимального значения size_t |
Сообщ.
#8
,
|
|
|
Любой контейнер имеет метод max_sixe(), но по Стандарту он ограничивает потенциал контейнера, т.е. без учёта фактических ограничений исполнительной подсистемы. И вообще-то это логично, т.к. последний зависит от многих факторов, выходящих за рамки Стандарта. Фактический же не имеет чёткой границы. Вот надо тебе только то, что умещается в памяти или же ты согласен на своп. Если согласен, то до какой степени. На HDD у тебя будут одни предпочтения, на SDD ты можешь себе позволить больше свопа, и ещё больше, если не SATA, а NVMe. Итп.
Добавлено Я как-то использовал такой код на WinAPI. Сорри, без комментов. Пользуйся, если надо. template <typename T> size_t getOptimizedSize() { if constexpr (sizeof(void*) > 4) { size_t size = std::numeric_limits<decltype(size)>::max(), oldSize = size; void *mem; do { mem = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (mem == NULL) { oldSize = size; size >>= 1; continue; } size_t newSize = (oldSize >> 1) + (size >> 1); oldSize = size; size = newSize; VirtualFree(mem, 0, MEM_RELEASE); } while (size != oldSize); size_t allocated = size; mem = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (mem == NULL) throw std::runtime_error("Ops!"); std::cout << "Allocated " << size << " bytes" << std::endl; do { if (SetProcessWorkingSetSize(GetCurrentProcess(), size, size) == FALSE) { oldSize = size; size >>= 1; continue; } size_t newSize = (oldSize >> 1) + (size >> 1); oldSize = size; size = newSize; } while (size != oldSize); if (SetProcessWorkingSetSize(GetCurrentProcess(), size, size) == FALSE) throw std::runtime_error("Ops 2!"); std::cout << "Residented " << size << " bytes" << std::endl; do { if (VirtualLock(mem, size) == FALSE) { oldSize = size; size >>= 1; continue; } size_t newSize = (oldSize >> 1) + (size >> 1); oldSize = size; size = newSize; VirtualUnlock(mem, oldSize); } while (size != oldSize); if (VirtualLock(mem, size) == FALSE) throw std::runtime_error("Ops 3!"); std::cout << "Locked " << size << " bytes" << std::endl; SetProcessWorkingSetSize(GetCurrentProcess(), size, size); VirtualFree((char*)mem + size, allocated - size, MEM_DECOMMIT); std::cout << "Ok" << std::endl; // <- тут бряк VirtualUnlock(mem, oldSize); SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1); VirtualFree(mem, 0, MEM_RELEASE); return size / sizeof(T); } return std::numeric_limits<size_t>::max() / sizeof(T); } Добавлено Запуск на домашней тачке (32Г RAM + NVMe) выдал: Allocated 91625968979 bytes Residented 22906492243 bytes Locked 15270994816 bytes Ok Добавлено P.S. Прикольно, но если во время пауз позапускать ещё копии, то вот результаты последовательных запусков, пока предыдущие всё ещё удерживают свои залоченные регионы: Allocated 68719476733 bytes Residented 6442450941 bytes Locked 4294967291 bytes Allocated 68719476733 bytes Residented 1610612733 bytes Locked 1073741819 bytes Allocated 68719476733 bytes Residented 536870909 bytes Locked 357913937 bytes Добавлено Не думаю, что Стандарт тут чем бы там ни было мог бы помочь. Это уже не его сфера ответственности. После всех выходов память занята на 24%. |
Сообщ.
#9
,
|
|
|
Всем спасибо. Qraizer, отдельный респект за тесты и пример. Я так понимаю, что Стандарт этим не занимается. Но и в этом вижу профит - не указывает, но и не ограничивает. Значит будем посмотреть в компиляторах.
|