From fbccb827d44dea653c80db848159ace2f8b5015d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20Kaan=20G=C3=9CM=C3=9C=C5=9E?= <96421894+Tahinli@users.noreply.github.com> Date: Sun, 22 Sep 2024 04:20:08 +0300 Subject: [PATCH] feat: :sparkles: finds and kills memory consumers when memory reaches critical level --- .gitignore | 6 ++- Cargo.toml | 7 +++ src/main.rs | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore index d01bd1a..efe3eb1 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,8 @@ Cargo.lock # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ \ No newline at end of file +#.idea/ + +# Added by cargo + +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4260c79 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "rust-memory-filler-killer" +version = "0.1.0" +edition = "2021" + +[dependencies] +sysinfo = "0.31.4" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..a7bb043 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,134 @@ +use std::{process::exit, thread::sleep, time::Duration}; + +use sysinfo::{Pid, System}; + +struct Input { + control_delay: u16, + dealloc_delay: u16, + include_swap: bool, + kill_threshold: f64, +} + +fn main() { + println!("Hello, world!"); + let input = get_parameters(); + let mut system = System::new_all(); + loop { + sleep(Duration::from_millis(input.control_delay as u64)); + if let Some(memory_filler) = find_memory_filler(&mut system, &input) { + kill_memory_filler(memory_filler, &mut system, &input) + } + } +} + +fn find_memory_filler(system: &mut System, input: &Input) -> Option { + system.refresh_all(); + let used_memory = system.used_memory() as f64; + let total_memory = if input.include_swap { + (system.total_memory() + system.total_swap()) as f64 + } else { + system.total_memory() as f64 + }; + if (used_memory / total_memory) >= input.kill_threshold { + let mut memory_filler = system.process(Pid::from_u32(1)).unwrap(); + for (_, process) in system.processes() { + if process.memory() > memory_filler.memory() { + memory_filler = process; + } + } + Some(memory_filler.pid()) + } else { + None + } +} + +fn kill_memory_filler(memory_filler: Pid, system: &mut System, input: &Input) { + let memory_filler = match system.process(memory_filler) { + Some(process) => process, + None => return, + }; + println!( + "Memory Filler = {} | Pid: {} | Used Memory: {} |\nUsed Memory Percentage: \n\tMemory -> %{}\n\tMemory + Swap -> %{}", + memory_filler.name().to_string_lossy(), + memory_filler.pid(), + memory_filler.memory() / (1024 * 1024), + memory_filler.memory() as f64 / system.total_memory() as f64, + memory_filler.memory() as f64 / (system.total_memory() + system.total_swap()) as f64 + ); + memory_filler.kill(); + memory_filler.wait(); + sleep(Duration::from_millis(input.dealloc_delay as u64)); +} + +fn get_parameters() -> Input { + let env_values = std::env::args().collect::>(); + let mut input = Input { + control_delay: 1000, + dealloc_delay: 1000, + include_swap: false, + kill_threshold: 0.95, + }; + let get_env_value = |env_values: &Vec, index: usize| -> Option { + env_values.get(index).map(|env_value| env_value.to_string()) + }; + let parse_env_value_to_u16 = + |env_value: Option| env_value.map(|env_value| env_value.parse::()); + let parse_env_value_to_bool = + |env_value: Option| env_value.map(|env_value| env_value.parse::()); + let parse_env_value_between_zero_and_one = |env_value: Option| { + env_value.map(|env_value| { + env_value.parse::().map(|parsed_value| { + if parsed_value > 1.0 { + return 1.0; + } else if parsed_value < 0.0 { + return 0.0; + } else { + parsed_value + } + }) + }) + }; + for (i, env_value) in env_values.iter().enumerate() { + match env_value.as_str() { + "--control_delay" | "-cd" => { + input.control_delay = parse_env_value_to_u16(get_env_value(&env_values, i + 1)) + .unwrap_or(Ok(input.control_delay)) + .unwrap_or(input.control_delay); + } + "--dealloc_delay" | "-dd" => { + input.dealloc_delay = parse_env_value_to_u16(get_env_value(&env_values, i + 1)) + .unwrap_or(Ok(input.dealloc_delay)) + .unwrap_or(input.dealloc_delay); + } + "--include_swap" | "is" => { + input.include_swap = parse_env_value_to_bool(get_env_value(&env_values, i + 1)) + .unwrap_or(Ok(input.include_swap)) + .unwrap_or(input.include_swap); + } + "--kill_threshold" | "kt" => { + input.kill_threshold = + parse_env_value_between_zero_and_one(get_env_value(&env_values, i + 1)) + .unwrap_or(Ok(input.kill_threshold)) + .unwrap_or(input.kill_threshold); + } + "--help" | "-h" => { + show_help(); + exit(0); + } + _ => {} + } + } + input +} + +fn show_help() { + println!("\n\n\n"); + println!("Arguments | Details | Defaults"); + println!("------------------------------------------------------------------------------"); + println!("-cd | --control_delay | Process Control Delay | 1000(ms)"); + println!("-dd | --dealloc_delay | Dealloc Delay, After Termination | 1000(ms)"); + println!("-is | --include_swap | Include Swap for Total Memory | false(bool)"); + println!("-kt | --kill_threshold | Memory Limit to Kill Process | 0.95(0.0-1.0)"); + println!("-h | --help | Shows Help"); + println!("\n\n\n"); +}