А в том, что и x87, и SSE - расширенные наборы инструкций, работающие со специализированными регистрами процессора. Они никак не затрагивают сердце процессора - его базовый набор инструкций (Instruction Set Architecture, ISA) и базовые регистры общего назначения (General Purpose Registers, GPR), равно как и некоторые «представления» процессора об окружающем его мире. Лирик, наверное, не упустил бы здесь возможности немного пофилософствовать на тему подобных «неощутимых» с первого взгляда, но очень глубоких по своей сути различий, но я не философ, а математик, и потому просто скажу, что на практике главное отличие GPR-регистров от всех остальных в том, что их можно использовать для адресации оперативной памяти. То есть 64-битный процессор - это не тот, который в принципе может работать с 64-битными числами (хотя это он тоже должен уметь делать, выполняя с 64-битными целыми числами все базовые арифметические операции), а тот, который способен этими числами «нумеровать» ячейки памяти.
Чтобы было понятнее, о чем идет речь, поясняю: стандартная модель записи целочисленных чисел позволяет записать в 32-разрядный GPR-регистр процессора архитектуры IA-32 любое целое число от 0 до 232-1. Оперативная память с точки зрения прикладных приложений представляется здесь в виде эдакой длинной ленты из ячеек определенного размера (1 байт в x86), причем все они «пронумерованы» - ячейка 0, ячейка 1 и так далее, вплоть до ячейки 4.294.967.295. Какие-то ячейки могут «отсутствовать» - в этом случае обращение к ним будет вызывать ошибку, однако потенциальная возможность обратиться к этой ячейке существует всегда. А вот у 32-разрядного процессора возможности обратиться к ячейке 4.294.967.295 нет в принципе - просто потому, что он не сможет «дать ей название».
Что это означает на практике? Только то, что ни одна «классическая» 32-битная программа не может использовать больше 4 Гбайт (232/210*210*210) памяти. Поэтому если вы спросите продавца о преимуществах 64-разрядного процессора, то именно эту сакральную фразу о «поддержке большого объема оперативной памяти» (вместе с вопросом «а оно вам надо?») и услышите. Но все-таки не спешите сводить эту возможность к установке в систему четырех двухгигабайтных планок SDRAM. Все далеко не так просто.
Первая «особенность», о которой часто забывают, рассматривая 64-разрядные процессоры, - это то, что во всех современных компьютерах программы работают не с физической, а с виртуальной оперативной памятью, то есть программная адресация памяти может не совпадать с действительным расположением этой памяти в компьютере. В нашей модели длинной ленты ячеек мы можем нумеровать их в произвольном порядке (0, 6533, 21, 554, 54223563, 2, …). Это очень удобно в многозадачных операционных системах: по-разному пронумеровав ячейки и раздав их разным приложениям (после чего в памяти образуется каша, когда данные разных программ лежат вперемешку), на логическом уровне мы сохраняем линейность и стройность, поскольку каждая программа работает не с этой кашей, а с виртуальным пространством адресов, в которое попадают данные только этой программы, и расположенные именно так, как программе привычно.
Впрочем, перенумерацией дело не ограничивается, поскольку вместе с номерами указываются всяческие атрибуты - «только для чтения», «только для операционной системы» и пр. Вдобавок для некоторых ячеек можно указать, что они в оперативную память «пока не загружены». Встретив такую пометку, CPU генерирует специальную системную ошибку (Page Fault) и обращается за помощью к операционной системе, которая может, к примеру, загрузить данные для этой ячейки с жесткого диска (техника своппинга). Поэтому всегда следует помнить, что «ограничение 4 Гбайт» в первую очередь относится не к физической, а к виртуальной оперативной памяти, доступной процессу. А вот что стоит за этими четырьмя гигабайтами адресного пространства - скромные ли 128 Мбайт памяти SDRAM или кусочек от пары терабайтов дискового массива - неважно: собственно процессор этот «реальный мир» почти ничем не ограничивает.
Но все же - что дает разрядность? Если процессор поддерживает длинные физические адреса (в архитектуре x86 соответствующий режим называется Physical Address Extension, PAE[Если подробнее, то в PAE используется 52-битная адресация, позволяющая адресовать до четырех петабайт данных]), то мы можем поставить на сервер хоть 64 Гбайт оперативной памяти и выделять ее разным приложениям. Условия вроде «не более двух гигов для чипсета такого-то» - это ограничения именно чипсета, не умеющего обслуживать большой объем памяти, а не 32-разрядной системы. Поэтому в серверных приложениях, когда на одном сервере, как правило, запущено несколько десятков одновременно работающих приложений, пресловутый «барьер в 4 Гбайт» практически не ощущается. Но означает ли это, что сегодня 64-разрядный x86 никому не нужен?
Конечно, нет! 64-разрядность виртуальной памяти в приложениях востребована уже сейчас, просто эти «добавочные биты» используются другими способами.
Во-первых, какую-то часть виртуального адресного пространства может забирать операционная система. К примеру, MS Windows обычно использует для своих нужд старший бит виртуального адреса, ограничивая адресное пространство запущенного в ней приложения 31 битом и 2 Гбайт адресного пространства. А два гигабайта оперативной памяти, согласитесь, куда ближе к реальной жизни, нежели гипотетические четыре; и ситуацию, когда их начнет не хватать, представить гораздо проще. Можно, правда, попытаться использовать специальный режим, когда Windows будет предоставлять процессам не два, а три гига адресного пространства, но работает он, к сожалению, далеко не всегда, зачастую роняя при неправильной настройке операционную систему.
Во-вторых, линейное адресное пространство подвержено «засорению» - процессу, в ходе которого в нем образуются дырки, которые невозможно использовать. Программы часто оперируют не байтами и словами, а гораздо более крупными структурами, занимающими десятки, сотни и даже миллионы байт информации. Если мы использовали эту структуру, а затем необходимость в ней отпала, то в памяти остается дыра, совпадающая по размерам и расположению с местом, где лежали данные этой структуры. И удастся ли сию дыру использовать - еще бабушка надвое сказала. Иногда почти вся оперативная память состоит из дырок, не несущих никакой практической пользы, и места для записи даже небольшого объема данных не находится[Подобным особенно грешат операционные системы и среды разработки компании Microsoft: менеджер памяти, используемый в Windows, не столь эффективен, как его UNIX-собратья, и «мусора» в памяти оставляет гораздо больше. Иногда это приводит к тому, что нормально работающие на UNIX программы, использующие вдобавок сравнительно небольшой объем оперативной памяти, в MS Windows через некоторое время вылетают с ошибкой Out of memory].
В-третьих, существует такая интересная техника, как маппинг файлов на оперативную память. «Маппить» можно что угодно, причем это не только самый быстрый, но и один из самых удобных способов обработки файлов. Не нужно ничего читать из файла или записывать в него, не нужно думать об эффективном кэшировании данных - все происходит автоматически. Просто «мапнул» файл на память - и находившиеся в нем данные волшебным образом мгновенно оказались доступными приложению. В «настоящую» оперативную память они будут подгружаться только при обращении к ним, а в случае длительной «невостребованности» - вновь возвращаться на жесткий диск, освобождая место для чего-нибудь более актуального. Реализовать что-либо подобное «вручную» - практически невозможно. Но, к сожалению, на двух гигабайтах адресного пространства Windows особенно не развернешься[И на 4 Гбайт своп-файла, которыми нас обычно ограничивает Windows (ругать так ругать!), - зачастую тоже], поэтому техника маппинга задействуется только тогда, когда высокая скорость обработки файлов для приложения становится критичной.