Распределение памяти массива - пейджинг - PullRequest
2 голосов
/ 26 октября 2011

Не уверен, что ответ будет одинаковым для Java, C # и C ++, поэтому я классифицировал их все.Ответ для всех языков был бы неплохим.

Все дни я думал, что если я выделю массив, все ячейки будут в одном непрерывном пространстве.Поэтому, если в одной системе недостаточно памяти, возникает исключение из памяти.

Все в порядке, что я сказал?Или есть вероятность, что выделенный массив будет разбит на страницы?

Ответы [ 6 ]

5 голосов
/ 26 октября 2011

Массивы C ++ являются смежными, что означает, что память имеет последовательные адреса, то есть она непрерывна в виртуальном адресном пространстве. Он не должен быть смежным в физическом адресном пространстве, поскольку современные процессоры (или их подсистемы памяти) имеют большую карту, которая связывает виртуальные страницы с физическими страницами. Процессы, работающие в пользовательском режиме, никогда не видят физических адресов своих массивов.

Я думаю, что на практике большинство или все реализации Java одинаковы. Но программист никогда не видит фактический адрес элемента массива, просто ссылку на массив и средства для его индексации. Таким образом, теоретически реализация Java может разбивать массивы и скрывать этот факт в операторе [], хотя код JNI может по-прежнему просматривать массив в стиле C ++, и в этот момент потребуется непрерывный блок. Предполагается, что в спецификации JVM нет ничего о компоновке массивов, что, по словам jarnbjo, отсутствует.

Я не знаю C #, но я ожидаю, что ситуация очень похожа на Java - вы можете представить, что реализация может использовать оператор [], чтобы скрыть тот факт, что массив не является смежным в виртуальном адресном пространстве. Притворство потерпит неудачу, как только кто-то получит указатель на него. [Редактировать: Полином говорит, что массивы в C # могут быть непрерывными, пока кто-то их не закрепит, что имеет смысл, так как вы знаете, что вам нужно закрепить объекты перед передачей их в низкоуровневый код, который использует адреса.]

Обратите внимание, что если вы выделяете массив какого-либо большого типа объекта, то в C ++ массив фактически состоит в том, что многие большие структуры заложены сквозным образом, поэтому требуемый размер непрерывного выделения зависит от размера объекта. В Java массив объектов является «действительно» массивом ссылок. Так что это меньший непрерывный блок, чем массив C ++. Для нативных типов они одинаковы.

2 голосов
/ 26 октября 2011

В C # вы не можете гарантировать, что блок памяти будет смежным. CLR пытается выделить память в одном непрерывном блоке, но он может выделить ее в нескольких блоках. Существует немного определенное поведение о том, как CLR должен управлять памятью C #, потому что он предназначен для абстрагирования управляемыми конструкциями.

Единственный раз, когда это действительно должно иметь значение в C #, это если вы передаете массив как указатель через P / Invoke на неуправляемый код, и в этом случае вы должны использовать GC.Pin для блокировки расположения объекта в памяти. Возможно, кто-то еще сможет объяснить, как CLR и GC справляются с необходимостью непрерывной памяти в этом случае.

1 голос
/ 26 октября 2011

С Java и C #, конечно.Мы можем показать это, запустив byte[] array = new byte[4097]; на компьютере с Windows, где размер страницы памяти составляет 4096 байт.Следовательно, он должен быть на нескольких страницах.

Конечно, подкачка влияет на производительность, но это может быть одним из случаев, когда GC, использующий такие среды, как .NET или Java, может иметь преимущество, потому что GC был написанлюди, которые знают, что пейджинг происходит.В структурах все еще есть преимущества, которые повышают вероятность наличия связанных элементов на одной странице (отдавая предпочтение коллекциям на основе массива по сравнению с коллекциями с отслеживанием указателей).Это также имеет преимущество с точки зрения кэшей процессора.(Большие массивы по-прежнему являются одним из лучших способов вызвать фрагментацию кучи, с которой GC должен бороться, тем не менее, поскольку GC довольно хорош в этом, это все равно будет победой над многими другими способами решения той же проблемы.).

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

1 голос
/ 26 октября 2011

В программах на C (++) обычно (то есть, если мы не говорим о интерпретации кода вместо его компиляции + непосредственного выполнения), массивы являются непрерывными в виртуальном адресном пространстве (если, конечно, существует такой вещь на рассматриваемой платформе).

Там, если большой массив не может быть выделен непрерывно, даже если имеется достаточно свободной памяти, вы получите либо исключение std :: bad_alloc (в C ++), либо NULL (из malloc () -подобных функций в C / C ++ или оператор броска, новый в C ++).

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

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

В системах без виртуальной памяти нет преобразования виртуальных адресов в физические, и ваша программа будет работать напрямую с физической памятью, следовательно, ей придется иметь дело с фрагментацией физической памяти, а также конкурировать с другими программами как за свободную память, так и за адресное пространство, что повышает вероятность сбоев выделения (системы с виртуальной памятью часто запускают программы в отдельных виртуальных адресных пространствах, и фрагментация в виртуальном адресном пространстве приложения A не влияет на работу приложения B).

1 голос
/ 26 октября 2011

В случае Java массив реализован как Object ....
и объект получает m / m только в куче ...
Так что я не уверен, но ..heap сделан только в RAM...

вы можете проверить .. IBM M / m

1 голос
/ 26 октября 2011

Все в порядке, что я сказал?

Верно, в Java и C #, но C ++ будет получать ошибку только тогда, когда вы достигнете предела процесса или системы.Разница в том, что в Java и C # это приложение накладывает ограничение на себя.В C ++ ограничение накладывается ОС.

Или есть вероятность, что выделенный массив будет разбит на страницы?

Это также возможно.Тем не менее, в Java наличие кучи очень плохо сказывается на производительности.Когда GC запускается, все проверенные объекты должны находиться в памяти.В C ++ это не очень хорошо, но имеет меньшее влияние.

Если вам нужны большие структуры, которые могут быть разбиты на страницы в Java, вы можете использовать ByteBuffer.allocateDirect () или файлы с отображением в памяти.Это работает с использованием памяти из кучи (в основном то, что использует C ++)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...