Context
There is a scrypt algorithm for deriving a key from password, sometimes called key stretching. Scrypt is a memory hard algorithm. Depending on parameters, scrypt may use 1GB of memory for key derivation (last test vector in rfc).
I am re-writing scrypt's C code in rust, and I have the following issues when allocating huge byte arrays.
Problem with vec allocation
I can use the following function to create a huge vector.
fn allocate_byte_array(len: usize) -> Vec<u8> {
let mut v: Vec<u8> = Vec::with_capacity(len);
unsafe {
v.set_len(len);
}
v
}
But, when I test run it, asking for 1GB, system monitor in my ubuntu 18 machine doesn't show that memory is allocated in one chunk. Instead, it seems that memory is lazily allocated.
In fact, you can allocate 100GB. This function will return. When you start to access memory, operating system starts to use it, all the way to the point of going frozen due to being out of memory.
In a playground running with aforementioned function
fn main() {
let v = allocate_byte_array(1024*1024*1024*100);
print!("size {}", v.len());
}
outputs size 107374182400
. We allocated 100GB on a server?
while the following
fn main() {
let mut v = allocate_byte_array(1024*1024*1024*100);
print!("size {}", v.len());
for i in 0..v.len() {
v[i] = i as u8;
}
}
is killed due to timeout (/root/entrypoint.sh: line 8: 7 Killed timeout --signal=KILL ${timeout} "$@"
).
Judging from system utilization graph, when an array is written it seems to be allocated in little chunks. But such multiple allocations are costly, especially for scrypt algorithm, when we need one huge allocation.
Comparable C code uses malloc that results in NULL, when requested length of an array is too big. Fast acquiring of memory or fast indication of failure is desirable in a given context.
Question
Is there a way to allocate huge chunk of memory in one round and use it as Vec<u8>
?
Is it possible to ensure that allocation fails immediately, when there is no memory?
Can this be done with some special allocator?