refactor: use Box to store large config objects and add memory usage tests

- Refactored config-related structs to use Box for storing large objects (e.g., IRuntime, IProfiles, PrfItem) to reduce stack memory usage and improve performance.
- Updated related methods and assignments to handle Boxed types correctly.
- Added and improved unit tests to compare memory usage between Boxed and non-Boxed config objects, demonstrating the memory efficiency of Box.
- Test output now shows the size difference between stack-allocated and heap-allocated (Box) config objects.
This commit is contained in:
Tunglies
2025-06-06 14:49:23 +08:00
parent 564fe15df2
commit 689042df60
6 changed files with 91 additions and 44 deletions

View File

@@ -15,10 +15,10 @@ pub const RUNTIME_CONFIG: &str = "clash-verge.yaml";
pub const CHECK_CONFIG: &str = "clash-verge-check.yaml";
pub struct Config {
clash_config: Draft<IClashTemp>,
verge_config: Draft<IVerge>,
profiles_config: Draft<IProfiles>,
runtime_config: Draft<IRuntime>,
clash_config: Draft<Box<IClashTemp>>,
verge_config: Draft<Box<IVerge>>,
profiles_config: Draft<Box<IProfiles>>,
runtime_config: Draft<Box<IRuntime>>,
}
impl Config {
@@ -26,26 +26,26 @@ impl Config {
static CONFIG: OnceCell<Config> = OnceCell::new();
CONFIG.get_or_init(|| Config {
clash_config: Draft::from(IClashTemp::new()),
verge_config: Draft::from(IVerge::new()),
profiles_config: Draft::from(IProfiles::new()),
runtime_config: Draft::from(IRuntime::new()),
clash_config: Draft::from(Box::new(IClashTemp::new())),
verge_config: Draft::from(Box::new(IVerge::new())),
profiles_config: Draft::from(Box::new(IProfiles::new())),
runtime_config: Draft::from(Box::new(IRuntime::new())),
})
}
pub fn clash() -> Draft<IClashTemp> {
pub fn clash() -> Draft<Box<IClashTemp>> {
Self::global().clash_config.clone()
}
pub fn verge() -> Draft<IVerge> {
pub fn verge() -> Draft<Box<IVerge>> {
Self::global().verge_config.clone()
}
pub fn profiles() -> Draft<IProfiles> {
pub fn profiles() -> Draft<Box<IProfiles>> {
Self::global().profiles_config.clone()
}
pub fn runtime() -> Draft<IRuntime> {
pub fn runtime() -> Draft<Box<IRuntime>> {
Self::global().runtime_config.clone()
}
@@ -149,11 +149,11 @@ impl Config {
pub async fn generate() -> Result<()> {
let (config, exists_keys, logs) = enhance::enhance().await;
*Config::runtime().draft() = IRuntime {
*Config::runtime().draft() = Box::new(IRuntime {
config: Some(config),
exists_keys,
chain_logs: logs,
};
});
Ok(())
}
@@ -164,3 +164,42 @@ pub enum ConfigType {
Run,
Check,
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem;
#[test]
fn test_prfitem_from_merge_size() {
let merge_item = PrfItem::from_merge(Some("Merge".to_string())).unwrap();
dbg!(&merge_item);
let prfitem_size = mem::size_of_val(&merge_item);
dbg!(prfitem_size);
// Boxed version
let boxed_merge_item = Box::new(merge_item);
let box_prfitem_size = mem::size_of_val(&boxed_merge_item);
dbg!(box_prfitem_size);
// The size of Box<T> is always pointer-sized (usually 8 bytes on 64-bit)
// assert_eq!(box_prfitem_size, mem::size_of::<Box<PrfItem>>());
assert!(box_prfitem_size < prfitem_size);
}
#[test]
fn test_draft_size_non_boxed() {
let draft = Draft::from(IRuntime::new());
let iruntime_size = std::mem::size_of_val(&draft);
dbg!(iruntime_size);
assert_eq!(iruntime_size, std::mem::size_of::<Draft<IRuntime>>());
}
#[test]
fn test_draft_size_boxed() {
let draft = Draft::from(Box::new(IRuntime::new()));
let box_iruntime_size = std::mem::size_of_val(&draft);
dbg!(box_iruntime_size);
assert_eq!(
box_iruntime_size,
std::mem::size_of::<Draft<Box<IRuntime>>>()
);
}
}