Недавно я хотел выделить вектор u64
s, выровненный по 128-байтовым границам, чтобы я мог использовать функции AVX512F. Мой первый проход функции для копирования любого Vec<u64>
в выровненный Vec<u64>
:
fn copy_to_aligned(inp: Vec<u64>) -> Vec<u64> {
// note: when the returned vec is freed, the alignment / layout information
// will be lost. The internal memory will be freed using the alignment
// of a u64.
let aligned_layout = Layout::from_size_align(inp.len() * size_of::<u64>(), 128)
.unwrap();
let new_vec = unsafe {
let new_vec_mem = alloc_zeroed(aligned_layout) as *mut u64;
copy_nonoverlapping(inp.as_ptr(), new_vec_mem, inp.len());
Vec::from_raw_parts(new_vec_mem, inp.len(), inp.len())
};
return new_vec;
}
Теперь я понимаю, что этот код неверен: пока новый вектор создается с выровненной памятью и соответствующим содержимым при отбрасывании нового вектора память будет освобождена с выравниванием u64
. Документация для from_raw_parts
также упоминает эту ловушку.
1) Почему выравнивание распределения имеет значение, когда я освобождаю это распределение? Например, в C я могу освободить любой указатель, просто вызвав free
- выравнивание распределения не имеет значения. Что особенного в распределителе Rust, что ему нужно знать выравнивание?
2) Как правильно распределить этот выровненный вектор? Должен ли я использовать срез в штучной упаковке? Напишите мою собственную структуру с пользовательской реализацией Drop
, которая дает правильное выравнивание? Другие источники предлагают создать структуру и указать выравнивание, а затем создать Vec
из этих структур (в результате чего для перераспределения будет использоваться правильный макет). Но даже с repr(C)
это не гарантирует, что все мои u64
s будут красиво и плотно упакованы рядом друг с другом, не так ли? Я полагаю, что произвольный отступ может быть добавлен в структуру.