Почему все используют 2 ^ n номера для распределения? → новый StringBuilder (256)
15 лет назад, программируя с Pascal, я понял, почему использовать мощность двух для распределения памяти. Но это все еще похоже на современное состояние.
Примеры С#:
new StringBuilder(256);
new byte[1024];
int bufferSize = 1 << 12;
Я все еще вижу это тысячи раз, я использую это сам, и я все еще спрашиваю:
Нужно ли нам это в современных языках программирования и современном оборудовании?
Я думаю, его хорошая практика, но какая причина?
ИЗМЕНИТЬ
Например, массив byte[]
, как указано в ответах здесь, мощность 2 не имеет смысла: сам массив будет использовать 16 байтов (?), Поэтому имеет смысл использовать 240 (= 256-16) для размер для 256 байтов?
Ответы
Ответ 1
Нужно ли нам это в современных языках программирования и современном оборудовании? Я думаю, его хорошая практика, но какая причина?
Это зависит. Здесь есть две вещи:
- Для размеров, меньших размера страницы памяти, нет заметной разницы между мощностью-2 и произвольным числом для выделения пространства;
- В основном вы используете управляемые структуры данных с С#, поэтому вы даже не знаете, сколько байтов действительно выделено под ним.
Предполагая, что вы выполняете низкоуровневое распределение с помощью malloc()
, использование кратных размера страницы будет считаться хорошей идеей, то есть 4096 или 8192; это связано с тем, что он обеспечивает более эффективное управление памятью.
Моим советом было бы просто выделить то, что вам нужно, и позволить С# обрабатывать управление и распределение памяти для вас.
Ответ 2
К сожалению, это довольно глупо, если вы хотите сохранить блок памяти на одной странице памяти 4k... И люди даже не знают об этом:-) (я не до 10 минут назад... У меня была только догадка)... Пример... Это небезопасный код и зависящий от реализации (с использованием .NET 4.5 на 32/64 бит)
byte[] arr = new byte[4096];
fixed (byte* p = arr)
{
int size = ((int*)p)[IntPtr.Size == 4 ? -1 : -2];
}
Таким образом, CLR выделил не менее 4096 + (1 или 2) sizeof (int)... Таким образом, он перешел на одну страницу памяти 4k. Это логично... Он должен хранить размер массива где-то, и держать его вместе с массивом - самая разумная вещь (для тех, кто знает, что Pascal Strings и BSTR
, да, это тот же принцип)
Я добавлю, что все объекты в .NET имеют номер синхронизации и RuntimeType
... Они не менее int
, если не IntPtr
, поэтому в общей сложности от 8 до 16 байт/объект (Это объясняется в разных местах... попробуйте найти .net object header
, если вы заинтересованы)
Ответ 3
В некоторых случаях это имеет смысл, но я бы предпочел проанализировать в каждом конкретном случае, нужна ли мне такая спецификация или нет, а не слепо использовать ее в качестве хорошей практики.
Например, могут быть случаи, когда вы хотите использовать ровно 8 бит информации (1 байт) для адресации таблицы.
В этом случае я бы позволил таблице иметь размер 2 ^ 8.
Object table = new Object[256];
Таким образом, вы сможете обращаться к любому объекту таблицы, используя только один byte
.
Даже если таблица на самом деле меньше и не использует все 256 мест, у вас все еще есть гарантия двунаправленного сопоставления из таблицы в индекс и из индекса в таблицу, что может помешать появлению ошибок, например, если вы было:
Object table = new Object[100];
И затем кто-то (возможно, кто-то другой) обращается к нему с байтовым значением вне диапазона таблицы.
Возможно, такое биективное поведение может быть хорошим, возможно, у вас могут быть другие способы гарантировать ваши ограничения.
Вероятно, учитывая увеличение умности современных компиляторов, это не единственная хорошая практика.
Ответ 4
ИМХО, все, что заканчивается точной мощностью двух арифметических операций, похоже на быстрый путь. низкоуровневая арифметическая операция для мощности двух принимает меньшее количество поворотов и манипуляций с битами, чем любые другие числа, требуют дополнительной работы для процессора.
И нашел этот возможный дубликат: Лучше ли распределять память в два раза?
Ответ 5
Да, это хорошая практика, и по крайней мере одна причина.
Современные процессоры имеют размер кеша L1 размером 64 байта, и если вы будете использовать размер буфера как 2 ^ n (например, 1024, 4096,..), вы будете использовать полностью кеш-строку, не теряя пространства.
В некоторых случаях это поможет предотвратить проблему ложного обмена (http://en.wikipedia.org/wiki/False_sharing).