Memory allocations

Why doesn't Vec trigger program break change in this code?

#![allow(unused_mut)]

use libc; // 0.2.132

fn main() {

    let mut ptr: [*mut char; 100000] = [0 as * mut _; 100000];

    let mut num_allocs = 1000; // default
    let mut block_size = 10240; // default

    let mut free_step = 1; // default
    let mut free_min = 500; // default

    let mut free_max = 1000; // default

    let mut j: usize = 0;
    
    
    program_break();


    unsafe {
        println!("Allocating {} x {} bytes", num_allocs, block_size);
        while j < num_allocs {
            ptr[j] = libc::malloc(block_size) as *mut _;
            if ptr[j].is_null() {
                panic!("malloc failed");
            }
            j += 1
        }

        program_break();

        println!(
            "Freeing blocks from {} to {} in steps of {}",
            free_min, free_max, free_step,
        );

        j = free_min - 1;

        while j < free_max {
            libc::free(ptr[j] as *mut _);
            j += free_step
        }

        program_break();
    }
    
    
    {
        let v = vec![10f64; 1_000_000];
        dbg!(v[0]);
        program_break();
    }
    
    program_break();
}

fn program_break() {
    let res = unsafe { libc::sbrk(0) };
    let r = res as u64;
    println!("Program break - {:p} -- {}", res, r);
}

A quick search surfaced this...

What's described in some of the comments has been my experience; that malloc calls mmap to get large chunks from the operating system then subdivides that space. In which case sbrk really can't work (there isn't a clean boundary; mmap places sections willy nilly).

5 Likes

This is without vec.

#![allow(unused_mut)]

use libc; // 0.2.132

fn main() {

    let mut ptr: [*mut char; 100000] = [0 as * mut _; 100000];

    let mut num_allocs = 1000; // default
    let mut block_size = 10240; // default

    let mut free_step = 1; // default
    let mut free_min = 500; // default

    let mut free_max = 1000; // default

    let mut j: usize = 0;
    
    
    program_break();


    unsafe {
        println!("Allocating {} x {} bytes", num_allocs, block_size);
        while j < num_allocs {
            ptr[j] = libc::malloc(block_size) as *mut _;
            if ptr[j].is_null() {
                panic!("malloc failed");
            }
            j += 1
        }

        program_break();

        println!(
            "Freeing blocks from {} to {} in steps of {}",
            free_min, free_max, free_step,
        );

        j = free_min - 1;

        while j < free_max {
            libc::free(ptr[j] as *mut _);
            j += free_step
        }

        program_break();
    }
}

fn program_break() {
    let res = unsafe { libc::sbrk(0) };
    let r = res as u64;
    println!("Program break - {:p} -- {}", res, r);
}

Outputs:

Program break - 0x559d06e6b000 -- 94132914008064
Allocating 1000 x 10240 bytes
Program break - 0x559d07831000 -- 94132924256256
Freeing blocks from 500 to 1000 in steps of 1
Program break - 0x559d0734d000 -- 94132919128064

You can clearly see program break moving.

Try libc::malloc(8_000_000) since that's what you're doing with the Vec.

1 Like

Yes the break doesn't move. I just found out that if it crosses mmap threshold, malloc uses mmap instead of sbrk.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.