memory_leak.rs 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #![allow(non_snake_case)]
  2. use dioxus::prelude::dioxus_core::NoOpMutations;
  3. use dioxus::prelude::*;
  4. use sysinfo::{ProcessRefreshKind, RefreshKind, System};
  5. // Regression test for https://github.com/DioxusLabs/dioxus/issues/3421
  6. #[tokio::test]
  7. async fn test_for_memory_leaks() {
  8. fn app() -> Element {
  9. let mut count = use_signal(|| 0);
  10. use_hook(|| {
  11. spawn(async move {
  12. loop {
  13. tokio::time::sleep(std::time::Duration::from_nanos(1)).await;
  14. let val = *count.peek_unchecked();
  15. if val == 70 {
  16. count.set(0);
  17. } else {
  18. count.set(val + 1);
  19. }
  20. }
  21. })
  22. });
  23. rsx! {
  24. for el in 0..*count.read() {
  25. div {
  26. key: "{el}",
  27. div {
  28. onclick: move |_| { println!("click"); },
  29. }
  30. AcceptsEventHandlerAndReadOnlySignal {
  31. event_handler: move |_| { println!("click"); },
  32. signal: el,
  33. }
  34. }
  35. }
  36. }
  37. }
  38. // Event handlers and ReadOnlySignals have extra logic on component boundaries that has caused memory leaks
  39. // in the past
  40. #[component]
  41. fn AcceptsEventHandlerAndReadOnlySignal(
  42. event_handler: EventHandler<MouseEvent>,
  43. signal: ReadOnlySignal<i32>,
  44. ) -> Element {
  45. rsx! {
  46. div {
  47. onclick: event_handler,
  48. "{signal}"
  49. }
  50. }
  51. }
  52. // create the vdom, the real_dom, and the binding layer between them
  53. let mut vdom = VirtualDom::new(app);
  54. vdom.rebuild(&mut NoOpMutations);
  55. let pid = sysinfo::get_current_pid().expect("failed to get PID");
  56. let refresh =
  57. RefreshKind::nothing().with_processes(ProcessRefreshKind::nothing().with_memory());
  58. let mut system = System::new_with_specifics(refresh);
  59. let mut get_memory_usage = || {
  60. system.refresh_specifics(refresh);
  61. let this_process = system.process(pid).expect("failed to get process");
  62. this_process.memory()
  63. };
  64. let initial_memory_usage = get_memory_usage();
  65. // we need to run the vdom in a async runtime
  66. for i in 0..=10000 {
  67. // wait for the vdom to update
  68. vdom.wait_for_work().await;
  69. // get the mutations from the vdom
  70. vdom.render_immediate(&mut NoOpMutations);
  71. if i % 1000 == 0 {
  72. let new_memory_usage = get_memory_usage();
  73. println!("iteration: {} memory usage: {}", i, new_memory_usage);
  74. // Memory usage might increase as arenas fill up, but it shouldn't double from the initial render
  75. assert!(new_memory_usage < initial_memory_usage * 2);
  76. }
  77. }
  78. }