Description
Problem
When compiling code with a loop, a server function, and some other bits and bobs, the compiler will continuously eat memory and eventually OOM. This occurs on my machine with 86GB of RAM free - it fully OOMs.
There's a few edits that prevent duplicating this - removing the onclick handler, and removing the loop around the div {}
both prevent this occurring, but in the larger app the only way to consistently prevent this was to remove the loop(?)
I do 50 here, but a loop of 0..1
is enough to cause a problem.
Once you do get a hang, the issue can crop up in places that it did not previously occur - you need to cargo clean
between each set of tests to ensure that you have a clean slate, otherwise you will get false positives in when things break.
You cannot reproduce this purely with clean builds - this only occurs during incremental rebuilds.
Steps To Reproduce
Note, for all compiles, cargo build --profile server-dev --verbose --features dioxus/server
suffices to reproduce - but this can be replicated with the dioxus CLI too. Just you can't as easily kill it and prevent the OOM killer stomping all over your machine with the dioxus CLI, as it sometimes fails to properly kill the processes when cancelling.
Steps to reproduce the behavior:
- Start with a basic bare-bones dioxus project, and copy the below code into
src/main.rs
- Compile - successful
- Comment out the line
use_effect(move || loaded.set("Yes"));
and rebuild - should be successful - Uncomment out that line and rebuild - hang and eventual OOM
Expected behavior
Dioxus should build just fine
Screenshots
Environment:
- Dioxus version: 0.6.3
- Rust version: 1.85.1 stable
- OS info: Arch Linux
- App platform: Web fullstack
Questionnaire
I'm interested in fixing this myself but don't know where to start. I don't know how much time I will have but if I do have time I'm happy to go for it.
Code:
use dioxus::prelude::*;
fn main() {
dioxus::launch(App);
}
#[server]
pub async fn notify_update(_v: Option<u32>) -> Result<u32, ServerFnError> {
Ok(0)
}
#[server]
pub async fn trigger_update() -> Result<(), ServerFnError> {
Ok(())
}
#[component]
fn App() -> Element {
let initial_state =
use_server_future(move || async move { notify_update(None).await.unwrap() })?;
let mut state = use_signal(|| initial_state.unwrap());
use_future(move || async move {
loop {
let old_state = *state.read();
let new_state = notify_update(Some(old_state)).await.unwrap();
state.set(new_state);
}
});
let mut loaded = use_signal(|| "No");
use_effect(move || loaded.set("Yes"));
rsx! {
button {
onclick: async |_| { trigger_update().await.unwrap(); }
}
div {
"{loaded}"
}
for _ in 0..50 {
div {}
}
}
}
Full example project: breakshit.zip