What are you trying to put in this vector, and how are you trying to use it afterwards? This makes a big difference, because initializing an array with something Copy
gets to take a massive shortcut.
Using Vec::with_capacity()
should take next to no time because it just allocates memory without even reading it. It's essentially the overhead of malloc()
checking its bookkeeping and bumping a couple counters to reserve some space for you.
The vec![]
macro will use the memset()
function from libc (std::ptr::write_byte()
in Rust), which is one of the most highly optimised functions in existence for setting every byte in an array (it's used in literally everything).
It may help to have some numbers, so I ran some benchmarks on my laptop.
Benchmark Code
#![feature(test)]
extern crate test;
use test::Bencher;
const SIZE: usize = 1_000_000;
#[bench]
fn vec_with_capacity(b: &mut Bencher) {
b.iter(|| Vec::<u8>::with_capacity(SIZE));
}
#[bench]
fn vec_with_capacity_and_pushing(b: &mut Bencher) {
b.iter(|| {
let mut vector = Vec::with_capacity(SIZE);
for _ in 0..SIZE {
vector.push(0);
}
vector
});
}
#[bench]
fn vec_macro(b: &mut Bencher) {
b.iter(|| vec![0_u8; SIZE]);
}
#[bench]
fn vec_with_capacity_and_memset(b: &mut Bencher) {
b.iter(|| {
let mut vector = Vec::<u8>::with_capacity(SIZE);
unsafe {
vector.set_len(SIZE);
std::ptr::write_bytes(vector.as_mut_ptr(), 0, SIZE);
}
vector
});
}
#[bench]
fn loop_and_push(b: &mut Bencher) {
b.iter(|| {
let mut vector = Vec::new();
for _ in 0..SIZE {
vector.push(0);
}
vector
});
}
For SIZE = 100_000
:
$ cargo bench
test loop_and_push ... bench: 694,413 ns/iter (+/- 10,511)
test vec_macro ... bench: 8,319 ns/iter (+/- 622)
test vec_with_capacity ... bench: 130 ns/iter (+/- 12)
test vec_with_capacity_and_memset ... bench: 8,501 ns/iter (+/- 987)
test vec_with_capacity_and_pushing ... bench: 696,194 ns/iter (+/- 41,419)
For SIZE = 1_000_000
:
$ cargo bench
test loop_and_push ... bench: 6,918,695 ns/iter (+/- 524,425)
test vec_macro ... bench: 88,073 ns/iter (+/- 15,316)
test vec_with_capacity ... bench: 132 ns/iter (+/- 9)
test vec_with_capacity_and_memset ... bench: 87,081 ns/iter (+/- 14,708)
test vec_with_capacity_and_pushing ... bench: 7,008,704 ns/iter (+/- 730,025)
For SIZE = 50_000_000
:
$ cargo bench
test loop_and_push ... bench: 634,253,227 ns/iter (+/- 24,916,167)
test vec_macro ... bench: 22,132 ns/iter (+/- 2,654)
test vec_with_capacity ... bench: 21,489 ns/iter (+/- 682)
test vec_with_capacity_and_memset ... bench: 81,422,411 ns/iter (+/- 8,883,889)
test vec_with_capacity_and_pushing ... bench: 644,344,068 ns/iter (+/- 43,302,454)
These numbers are useless at best, and quite possibly misleading without more information on your use case.
Something that may help is to change your algorithm to make it lazy (generate data on demand) instead of allocating upfront. Or try to identify why you need so much memory (100 million is a big number!) and see if it's possible to make do with less.