GuillaumeGomez / sysinfo

Cross-platform library to fetch system information
MIT License
2.06k stars 307 forks source link

There is a memory leak when I call with cgo #944

Closed polin-x closed 1 year ago

polin-x commented 1 year ago
#[no_mangle]
pub extern "C" fn get_processlist() -> *mut c_char {
    sysinfo::set_open_files_limit(0);
    let mut v: Vec<ProcessStruct> = Vec::new();
    let mut sys = sysinfo::System::new_all();
    sys.refresh_all();
    std::thread::sleep(System::MINIMUM_CPU_UPDATE_INTERVAL);
    sys.refresh_all();

    for (i, process) in sys.processes() {
        let p = ProcessStruct {
            pid: i.as_u32(),
            name: process.name().to_string(),
            memory: process.memory().to_le(),
            start_time: process.start_time().to_le(),
            used_cpu: process.cpu_usage(),
            disk_usage: DiskUsage {
                total_written_bytes: process.disk_usage().total_written_bytes,
                written_bytes: process.disk_usage().written_bytes,
                total_read_bytes: process.disk_usage().total_read_bytes,
                read_bytes: process.disk_usage().read_bytes,
            },
        };
        v.push(p);
    }

    v.sort_by(|a, b| b.memory.cmp(&a.memory));

    let json_string = match serde_json::to_string(&v) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to serialize JSON: {}", e);
            return std::ptr::null_mut();
        }
    };

    v.shrink_to_fit();
    let c_string = match CString::new(json_string) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to create CString: {}", e);
            return std::ptr::null_mut();
        }
    };

    c_string.into_raw()
}

#[no_mangle]
pub extern "C" fn free_string(s: *mut c_char) {
    unsafe {
        if s.is_null() {
            return;
        }
        CString::from_raw(s)
    };
}
    ticker := time.Tick(time.Millisecond * 300)
    for range ticker {
        go func() {
            ptr := C.get_processlist()
            str := C.GoString(ptr)
            fmt.Println(str)
            defer C.rust_free_string(ptr)
        }()

    }
GuillaumeGomez commented 1 year ago

Do you have more information on the leak by any chance?

polin-x commented 1 year ago

Do you have more information on the leak by any chance?

How can I get it, I am not familiar with rust memory analysis

GuillaumeGomez commented 1 year ago

Valgrind or any equivalent will provide the information. I can't guess just from what you showed me.

polin-x commented 1 year ago

It is caused by this line let mut sys = sysinfo::System::new_all(); I don’t know if the relevant memory needs to be released after use

GuillaumeGomez commented 1 year ago

Normally no, thanks to how Rust memory is managed. However, this is not this line but something allocated inside this method. Try running with more valgrind options to get a more precise location (normally valgrind suggests a few itself).

However, I still have no idea of your OS (even though I suppose it's Linux since you're using set_open_files_limit).

Also a side-note: this code:

    let mut sys = sysinfo::System::new_all();
    sys.refresh_all();
    std::thread::sleep(System::MINIMUM_CPU_UPDATE_INTERVAL);
    sys.refresh_all();

can be reduced to:

    let mut sys = sysinfo::System::new_all();
    std::thread::sleep(System::MINIMUM_CPU_UPDATE_INTERVAL);
    sys.refresh_all();

new_all already get all updated information, so no need to call refresh_all right after it.

polin-x commented 1 year ago

I found that the same code works fine on macos (intel) and has problems on M1 Pro

GuillaumeGomez commented 1 year ago

That's weird. But in this case, I can't help since I don't have a M1...

polin-x commented 1 year ago

I'll just change it to a different way of writing it.

lazy_static! {
    static ref SYS: Mutex<System> = Mutex::new(System::new_all());
}

fn xxx() {
    let mut sys = SYS.lock().unwrap();
    sys.refresh_all();
    drop(sys);
}
GuillaumeGomez commented 1 year ago

I couldn't find a leak so closing (on mac). Don't hesitate to re-open if you can find where it comes from.