Skip to content

Memory Leak #160

Open
Open
@ManeraKai

Description

@ManeraKai

I simplified it as much as possible. Here's my Cargo.toml

[package]
name = "geos-geometry"
version = "0.1.0"
edition = "2021"

[dependencies]
geos = "9.0.0"
rocket = "0.5.1"

main.rs:

#[macro_use]
extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    let _: Vec<geos::Geometry> = (0..2_000_000)
        .map(|_| geos::Geometry::create_empty_point().unwrap())
        .collect();

    "finished"
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![index])
}

GEOS version: 3.12.1-CAPI-1.18.1

Every time I request curl http://127.0.0.1:8000/, I get a +3GB spike in memory. It never frees it. It continues allocating more and more until my OS runs out of memory and crashes. I'm on Ubuntu 24.04.

If you think this is related to rocket, I don't think it is. Here's a code where I only used Vec<i64>:

#[macro_use]
extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    let n: i64 = 1_000_000_000;
    let mut array: Vec<i64> = Vec::with_capacity(n as usize);
    for i in 0..n {
        array.push(i);
    }
    "finished"
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![index])
}

This code spikes memory to about 7GB, but it instantly frees after the request is completed.

Here's the geos-sys version:

use geos::sys::{
    GEOSGeom_createEmptyPoint_r, GEOSGeom_destroy_r, GEOSGeom_t, GEOS_finish_r, GEOS_init_r,
};

#[macro_use]
extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    let ctx = unsafe { GEOS_init_r() };

    let n = 10_000_000;
    let mut geometries: Vec<*mut GEOSGeom_t> = Vec::with_capacity(n);

    for _ in 0..n {
        let geom;
        unsafe {
            geom = GEOSGeom_createEmptyPoint_r(ctx);
        }
        geometries.push(geom);
    }

    for geom in geometries {
        unsafe {
            GEOSGeom_destroy_r(ctx, geom);
        }
    }

    unsafe {
        GEOS_finish_r(ctx);
    }

    "finished"
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![index])
}

Interesting, but why geos::Geometry::create_empty_point() creates a separate context for each new geometry? According to GEOS_init_r(), the context should be passed to other _r functions. I think that's using a lot of memory.
In this geos-sys code, I was able to create 10 million points and only take up 1GB. The memory usage spiked from 1GB, 2GB, 3GB, and then it stayed on 3GB.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions