new[]
дает нам последовательную память.
C++23 проект N4928, глава 6.7.5.5.2 (2) «Функции распределения», выделение мое:
Функция распределения пытается выделить запрошенный объем памяти. В случае успеха он возвращает адрес начала блока памяти, длина которого в байтах не меньше запрошенного размера.
Указывает ли спецификация C++, находится ли этот блок памяти на самом деле в физической оперативной памяти после выделения, или он может находиться только в виртуальной оперативной памяти и, таким образом, полностью или частично выгружаться на диск?
Origin of this question is a discussion in the comments of this question.
Ничто в стандарте C++ не указывает на это. У него очень абстрактное представление об аппаратном обеспечении. Однако, основываясь на недавних вопросах, я могу сказать, что на практике память, возвращаемая new
, может находиться в виртуальной памяти. Кроме того, «в виртуальной памяти» не означает «выгружено на диск», по крайней мере, в Windows.
Стандарт C++ нацелен на Абстрактную машину, которая не заботится о физической/виртуальной памяти. «...Семантические описания в этом документе определяют параметризованную недетерминированную абстрактную машину. Этот документ не предъявляет никаких требований к структуре соответствующих реализаций. В частности, им не нужно копировать или эмулировать структуру абстрактной машины. Скорее, соответствующие реализации являются требуется эмулировать (только) наблюдаемое поведение абстрактной машины, как описано ниже...».
Где на самом деле расположена память, зависит от ОС, а не от самого C++.
@PepijnKramer, насколько я понимаю, это тоже. Это могло бы быть даже в облаке, если бы Microsoft решила реализовать это в качестве альтернативы подкачке на диск.
А когда дело доходит до ОС, Linux может при обстоятельствах согласиться даже на необоснованное распределение, которое невозможно удовлетворить, используя всю доступную память. Распределение, похоже, будет успешным, вы получите кучу нерезидентных страниц, и ваша программа будет уничтожена позже, только если она попытается записать слишком много из них.
Также помните, что некоторые ОС и/или оборудование даже не поддерживают виртуальную память, и ваш код C++ будет выглядеть так же. Меня больше интересует, почему вы хотите это знать? Это из-за каких-то проблем с производительностью или просто из любопытства? :)
@PepijnKramer: это в основном из-за нового комментария Питера, в котором говорится, что два std::vector (старый вектор до перераспределения и новый вектор) должны оба находиться в оперативной памяти. Сомневаюсь.
Определенно было бы более эффективно иметь оба варианта в физической оперативной памяти одновременно. Но AFAIK, это не то, как работает подкачка памяти: если есть ошибка страницы, страница заменяется другой страницей (в соответствии с некоторой стратегией)... так что вполне может быть, что после копирования оба вектора находятся в ОЗУ (если ОЗУ достаточно большая ). Таким образом, копирование может замедлиться до такой степени, что его станет невозможно использовать из-за уничтожения... но пока достаточно виртуальной памяти, я не понимаю, почему копирование не удастся. (Но опять же, то, как это действительно работает, зависит от ОС)
@ThomasWeller они не обязательно должны быть оба в физической оперативной памяти. Питер здесь неправ. Они оба должны помещаться в свободном адресуемом пространстве, которым обычно является адресуемая пользователем виртуальная память, но это не обязательно. В том примере DOS, который вы упомянули, в модели крошечной памяти std::vector не сможет изменить размер, прежде чем он достигнет размера даже 32 КБ, хотя его max_size(), вероятно, укажет 64 КБ максимального полезного пространства.
C++ на самом деле не имеет дело с физическими машинами. Он нацелен на некую абстрактную машину, имеющую некую унифицированную память. В стандарте C++ не существует таких понятий, как физическая или виртуальная память, поэтому он не может указывать ни один из способов. Итак, это ответ на ваш вопрос, как он задан.
Теперь, если бы вы спросили: «Будет ли моя новая [] выделенная память в реальности выделена в физической памяти?», ответ будет: «Это зависит от среды». Например, ваша программа на C++ может быть нацелена на какой-нибудь микроконтроллер, например ARM Cortex M3, у которого нет MMU. В этом случае new[]
предоставит вам кусок непрерывной физической памяти по указанному вам адресу (и там вообще нет понятия виртуальной памяти, поэтому ваш вопрос не имеет смысла в этой среде). Вы можете настроить DOS, и в этом случае вы также получите непрерывную физическую память по указанному вам адресу (если только ваша программа не работает под каким-либо VDM, например, в Windows, и в этом случае она не получает физическую память). Вы можете настроить таргетинг на какую-нибудь ОС с MMU, но без подкачки или распределения по требованию. В этом случае вы получите непрерывную виртуальную память, поддерживаемую физической памятью, но эта физическая память может не быть непрерывной, и вы не будете знать ее адрес. Наконец, вы можете ориентироваться на какую-нибудь «обычную» среду ОС с MMU и подкачкой, например Linux — и в этом случае вы получите виртуальную память, которая может не поддерживаться физической памятью (в случае Linux, в котором есть подкачка по требованию — вы я определенно не получу физическую память для большей части возвращенного блока виртуальной памяти)
В старом DOS (не в 32-битном расширенном) вы даже не могли выделить более одной страницы за раз. Таким образом, ваша физическая память была больше, чем вы могли выделить (за один раз) на практике. Так что да, аппаратные ограничения могут «просачиваться»
Ну, технически вы могли бы. Могла быть реализация, которая бы использовала 32-битный size_t и огромные указатели по умолчанию, а также fmemcpy
для memcpy
, fmalloc
для malloc
и т. д. Я думаю, что у watcom была огромная модель памяти? Просто обычно это делалось не из соображений производительности. Проблемы с аппаратной реализацией возникают не только в конкретных реализациях C++, но даже формируют сам стандарт (все ограничения на указатели связаны с тем, что они, возможно, сегментированы, или, например, когда подписанное переполнение стало законным и почему оно было незаконным раньше?)
Да, я помню модели памяти большего размера... даже ошибки в них (например, в одном компиляторе смещение все еще составляло 16 бит). И, конечно же, аппаратное обеспечение во многом налагает стандарты C++, большая часть UB тоже связана с этим. И watcom на x386 позволял переключиться в 32-битный режим... но с обработчиками прерываний было сложно... Хаха, те «добрые» старые времена ;) (где вы, по крайней мере, могли еще рассуждать о том, как на самом деле работает память/ЦП)
Терминологическое примечание: MMU -> Блок управления памятью.
Обычно различие между виртуальной и физической памятью не происходит на уровне приложения, поэтому я был бы удивлен, если бы это вообще обсуждалось в проекте C++.