Во-первых, для 3904 ГБ памяти требуется только 42 бита для адресации. Он состоит только из 3 904 000 000 000
байтов вместо того, что вы рассчитали
PS C:\> [math]::Log(3904GB, 2) 41.9307373375629
Технически, даже на 64-битной машине, если вы используете менее чем ~ 4 миллиарда целых чисел (максимальный размер 32-битного целого), то мне интересно, почему вы не можете просто указывать 32-битные указатели. Таким образом, указатели будут 32-битными, пока вы не исчерпаете пространство, тогда вы можете начать использовать 64-битные указатели. Тогда это даст вам немного больше места для большего количества объектов.
x32 ABI - это 64-битный x86 ABI, использующий 32-битные указатели. Процессы имеют только 32-разрядное адресное пространство, что означает, что они не могут использовать более 4 ГБ памяти (это не проблема для большинства пользовательских приложений), но они смогут использовать все большее и большее пространство регистров. Пространство глобальной памяти по-прежнему составляет 64 бита, поскольку оно фиксировано аппаратно, поэтому 32-разрядный указатель будет использоваться в качестве смещения к базовому адресу процесса вместо прямого указателя. Реализация просто так
void* getRealPointer(uintptr_t base_addr, uint32_t ptr) { return (void*)(base_addr + ptr); // value stored in pointer is the offset/distance from base }
Этот метод также распространен во многих других 64-разрядных архитектурах, таких как Sparc ( почему Linux на архитектуре sparc64 использует 32-разрядные указатели в пользовательском пространстве и 64-разрядные указатели в пространстве ядра? ), MIPS или PowerPC, поскольку на переходном этапе до 64-битных они не увеличили количество регистров, таких как x86 и ARM, что означает, что 32-битный процесс, вероятно, быстрее, чем 64-битный, если ему не требуется 64-битная математика или более 2/3 / 4ГБ баран
На 64-разрядных процессорах, таких как G5, Debian PPC использует 64-разрядное ядро с 32-разрядным пользовательским пространством. Это связано с тем, что 64-разрядные процессоры PowerPC не имеют «32-разрядного режима», как архитектура Intel 64 / AMD64. Следовательно, 64-разрядные программы PowerPC, которым не нужны 64-разрядные математические функции, будут работать несколько медленнее, чем их 32-разрядные аналоги, поскольку 64-разрядные указатели и длинные целые числа занимают вдвое больше памяти, быстрее заполняют кэш ЦП и, следовательно, требуют большего частые обращения к памяти.
https://lwn.net/Articles/395894/
Тем не менее, вы не можете просто использовать 32-битные указатели until you run out of space then start using 64-bit pointers
, это не имеет смысла. Тип всегда имеет фиксированный размер. Если вы зарезервируете место только для 32-битного указателя, что произойдет, если вам нужно использовать 64-битные указатели? Где вы будете хранить верхнюю часть?
Поэтому, если бы у нас были 32-разрядные указатели, указывающие на 32-разрядные фрагменты в 64-разрядной памяти, я не уверен, как это будет выглядеть или иметь в виду
Это называется адресной памятью . Вместо того, чтобы указывать на каждый байт, теперь каждое значение просто указывает на другое слово
Будет проще представить, что память состоит из серии линейных ячеек, которые идентифицируются уникальными идентификаторами. Эти идентификаторы - это то, что мы обычно называем «адрес», и то, что хранится в указателях. Размер ячейки обычно составляет 1 байт в современных системах (т. Е. Адресно-байтовая память). Однако многие старые системы, такие как Unisys или PDP, используют адресную память со словом, в котором ячейка содержит слово (в случае этих архитектур 36 бит длиной). Поэтому в этих системах char*
будет больше, чем, int*
поскольку вам понадобится еще несколько бит для хранения позиции байта, к которому вы хотите обратиться
Я не совсем понимаю вашу диаграмму, но людям редко приходится обращаться с каждым таким битом, так как это, очевидно, уменьшает общий объем памяти, который мы можем адресовать. Хотя, честно говоря, существует несколько архитектур с битовой адресацией памяти, в основном встроенные системы. Если выглядит так, как будто вы хотите получить 32-битное младшее 64-битное значение, когда вы назначаете процессору 32-битный адрес, но это не сработает. Для адресации каждой половины вам понадобится еще один значащий бит вместо половины количества битов, подобных этому. Принцип прост: если мы используем больший размер ячейки, чем в том же объеме памяти, требуется меньше ячеек, что означает, что для идентификатора требуется меньше битов; и наоборот. На аппаратном уровне размер ячейки обычно фиксирован.
Ниже приведен пример для первых 16 байтов в памяти
╔══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╗ ║ 0000 │ 0001 │ 0010 │ 0011 │ 0100 │ 0101 │ 0110 │ 0111 │ 1000 │ 1001 │ 1010 │ 1011 │ 1100 │ 1101 │ 1110 │ 1111 ║ ╠══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╣ ║ b0 │ b1 │ b2 │ b3 │ b4 │ b5 │ b6 │ b7 │ b8 │ b9 │ b10 │ b11 │ b12 │ b13 │ b14 │ b15 ║ ╟──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────╢ ║ w0 000 │ w1 001 │ w2 010 │ w3 011 │ w4 100 │ w5 101 │ w6 110 │ w7 111 ║ ╟─────────────┴─────────────┼─────────────┴─────────────┼─────────────┴─────────────┼─────────────┴─────────────╢ ║ dw0 00 │ dw1 01 │ dw2 10 │ dw3 11 ║ ╟───────────────────────────┴───────────────────────────┼───────────────────────────┴───────────────────────────╢ ║ o0 │ o1 ║ ╚═══════════════════════════════════════════════════════╧═══════════════════════════════════════════════════════╝
Вы также можете посмотреть на иллюстрации в этом ответе
Если мы обращаемся к каждому 2-байтовому слову, тогда N-е слово будет иметь байтовый адрес как N * 2. То же самое для любых других размеров чанка, где реальное смещение может быть вычислено как offset*sizeof(chunk)
. В результате 2 младших бита в 4-байтовом выровненном адресе 3 младших бита в 8-байтовом выровненном адресе всегда равны нулю. Если вы не используете адресно-адресные указатели, то эти младшие биты можно использовать для хранения данных, которые называются теговыми указателями.
64-битная JVM использует эту технику со сжатыми Oops . См. Хитрость, лежащую в основе сжатых Oops объектов JVM в Java, всегда выровненных по 8 байтов, поэтому они могут адресовать 8 * 4 = 32 ГБ памяти с 32-битным адресом.
Управляемые указатели в куче Java указывают на объекты, которые выровнены по 8-байтовым границам адресов. Сжатые операции представляют управляемые указатели (во многих, но не во всех местах в программном обеспечении JVM) как 32-битные смещения объектов из 64-битного базового адреса кучи Java. Поскольку это смещения объектов, а не смещения байтов, их можно использовать для адресации до четырех миллиардов объектов (не байтов) или размера кучи до 32 гигабайт. Чтобы использовать их, они должны быть масштабированы в 8 раз и добавлены к базовому адресу кучи Java, чтобы найти объект, к которому они относятся. Размеры объектов, использующих сжатые значения, сравнимы с размерами в режиме ILP32.
https://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#compressedOop
Инструкции, работающие с немедленным обращением в большинстве архитектур RISC, также хранят слово address, поскольку нет смысла тратить драгоценное пространство, экономя эти всегда нулевые биты. Например, инструкции MIPS для ветвления и перехода : JAL, J, BEQ, BLEZ, BGTZ ...