Размер массивов в MemoryLayout.size в Swift

Извините, если вопрос может повторяться, я не смог найти его ни здесь, ни с помощью Google.

Я новичок в небезопасном Swift, и мне было интересно, почему размер массива Bools, который составляет, например, 10 байтов, по-прежнему составляет 8 байтов?

Если бы я не мог сказать, что я имел в виду, мне было бы интересно, не могли бы вы взглянуть на этот код:

var boolArray = [Bool]()
for _ in 1...10{
    boolArray.append(true)
}
print(MemoryLayout.size(ofValue: boolArray))

Я не понимаю, почему он печатает 8, в то время как массив имеет 10 логических значений, которые содержат как минимум 10 байтов.


person Parsa Noori    schedule 26.02.2020    source источник
comment
Вам нужно всего 2 байта для хранения 16 бит. 1 байт равен 8 битам   -  person Leo Dabus    schedule 26.02.2020
comment
Несвязанный, но полезный: вы можете сократить генерацию этого массива до Array(repeating: true, count: 10) Или, если вы имеете дело с классами и хотите 10 различных объектов: (1...10).map { _ in YourClass() }   -  person Alexander    schedule 26.02.2020
comment
@LeoDabus Array<Bool> (в настоящее время) не занимается упаковкой битов. Он использует 1 байт Bools.   -  person Alexander    schedule 26.02.2020
comment
Я этого не говорил. Просто его формулировка не верна.   -  person Leo Dabus    schedule 26.02.2020
comment
@LeoDabus Эта запятая, которую я добавил в этом редактировании, решает вашу проблему?   -  person Parsa Noori    schedule 26.02.2020
comment
У меня нет проблем. Я просто сказал, что вам не нужно хотя бы 10 байт   -  person Leo Dabus    schedule 26.02.2020
comment
@Alexander-ReinstateMonica Спасибо, что напомнили, я просто забыл.   -  person Parsa Noori    schedule 26.02.2020
comment
@LeoDabus Ты лучший из всех прав - технически прав   -  person mag_zbc    schedule 26.02.2020
comment
@LeoDabus Если я ошибаюсь, поправьте меня. Наименьшая адресная единица в компьютерах составляет 1 байт, поэтому для хранения даже байтов требуется не менее 1 байта, а для массива из 10 логических значений требуется 10 байтов, а не 10 бит.   -  person Parsa Noori    schedule 26.02.2020
comment
@ParsaNoori Технически вы не можете загрузить что-то меньшее, чем строка кэша на современных процессорах. Но вы все еще можете получить доступ к избирателям. Хотя вы не можете загрузить отдельный бит, вы можете загрузить целый байт, замаскировать все биты, кроме того, который вы ищете, и прочитать его.   -  person Alexander    schedule 26.02.2020
comment
@ParsaNoori Поскольку в каждом байте 8 бит, вы можете использовать все, кроме последних 3 бит индекса, чтобы выбрать, какой байт просматривать, и использовать последние 3 бита для кодирования местоположения интересующего вас бита. Например, если вы хотите Bool в индексе 59 (0b111011 в двоичном формате), вы смотрите на 7-й байт (0b111). Допустим, значение этого байта было 0b11111111 (все верно). Нам важен бит 3 (0b011), поэтому мы маскируем 0b1111111, объединяя его с маской 0b00000100. Результат 0b00000100, что означает, что был установлен 3-й бит.   -  person Alexander    schedule 26.02.2020
comment
@ParsaNoori Если бы вместо этого байт имел значение 0b11111011, после маскирования его с помощью 0b00000100 мы получили бы 0x00000000, что означает, что 3-й бит был выключен.   -  person Alexander    schedule 26.02.2020
comment
@Alexander-ReinstateMonica Полностью принято, но, поскольку компилятор так не работает, стоит ли реализовывать эти низкоуровневые работы вместо того, чтобы просто использовать реализованные логические значения в самом языке, в то время как современная память содержит намного больше, чем количество этих слов?   -  person Parsa Noori    schedule 26.02.2020
comment
@ParsaNoori Во-первых, компилятор может упаковывать битовые шаблоны, и он делает это постоянно. Например, Optional<Bool> — это всего лишь 1 байт. Он кодирует false как 0b00, true как 0b01 и nil как 0b10.. Просто так получилось, что не для Array<Bool>. Кроме того, битовые поля по-прежнему чрезвычайно важны, даже при современных объемах памяти. Например, они повсеместно используются в игровых движках для определения того, какие слои могут физически взаимодействовать с какими другими слоями. .   -  person Alexander    schedule 26.02.2020
comment
@Alexander-ReinstateMonica Большое спасибо, мне очень помогли   -  person Parsa Noori    schedule 26.02.2020


Ответы (2)


Потому что результат функции size не включает в себя динамически выделенную или внестрочную память. См. https://developer.apple.com/documentation/swift/memorylayout/2486283-size

person hell0friend    schedule 26.02.2020

Это потому, что сам Array на самом деле ничего не хранит - внутри они содержат ссылку на выделенную кучей часть памяти, которая действительно хранит данные.

Одной из причин, по которой это сделано, является оптимизация — это позволяет использовать механизм копирования при записи. Array — это struct, поэтому это тип значения. Однако данные, которые он содержит, не нужно копировать каждый раз, когда вы копируете Array — вместо этого несколько Arrays могут указывать на одну и ту же область памяти, если они не изменяют ее.

person mag_zbc    schedule 26.02.2020
comment
Разумно предположить, что структура данных, представляющая Array контейнер, имеет длину 8 байт. Это непрозрачная структура, представляющая интерес только для разработчиков языка. - person Mike Robinson; 26.02.2020
comment
@MikeRobinson Напротив, его внутренняя работа увлекательна и может представлять большой интерес для многих, кто никогда не касался языкового дизайна (включая меня). - person Alexander; 26.02.2020