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

@@ -9,13 +9,21 @@ pub struct Draft<T: Clone + ToOwned> {
macro_rules! draft_define {
($id: ident) => {
impl Draft<$id> {
impl From<$id> for Draft<$id> {
fn from(data: $id) -> Self {
Draft {
inner: Arc::new(Mutex::new((data, None))),
}
}
}
impl Draft<Box<$id>> {
#[allow(unused)]
pub fn data(&self) -> MappedMutexGuard<$id> {
pub fn data(&self) -> MappedMutexGuard<Box<$id>> {
MutexGuard::map(self.inner.lock(), |guard| &mut guard.0)
}
pub fn latest(&self) -> MappedMutexGuard<$id> {
pub fn latest(&self) -> MappedMutexGuard<Box<$id>> {
MutexGuard::map(self.inner.lock(), |inner| {
if inner.1.is_none() {
&mut inner.0
@@ -25,7 +33,7 @@ macro_rules! draft_define {
})
}
pub fn draft(&self) -> MappedMutexGuard<$id> {
pub fn draft(&self) -> MappedMutexGuard<Box<$id>> {
MutexGuard::map(self.inner.lock(), |inner| {
if inner.1.is_none() {
inner.1 = Some(inner.0.clone());
@@ -35,7 +43,7 @@ macro_rules! draft_define {
})
}
pub fn apply(&self) -> Option<$id> {
pub fn apply(&self) -> Option<Box<$id>> {
let mut inner = self.inner.lock();
match inner.1.take() {
@@ -48,14 +56,14 @@ macro_rules! draft_define {
}
}
pub fn discard(&self) -> Option<$id> {
pub fn discard(&self) -> Option<Box<$id>> {
let mut inner = self.inner.lock();
inner.1.take()
}
}
impl From<$id> for Draft<$id> {
fn from(data: $id) -> Self {
impl From<Box<$id>> for Draft<Box<$id>> {
fn from(data: Box<$id>) -> Self {
Draft {
inner: Arc::new(Mutex::new((data, None))),
}
@@ -71,12 +79,12 @@ draft_define!(IRuntime);
draft_define!(IVerge);
#[test]
fn test_draft() {
let verge = IVerge {
fn test_draft_box() {
let verge = Box::new(IVerge {
enable_auto_launch: Some(true),
enable_tun_mode: Some(false),
..IVerge::default()
};
});
let draft = Draft::from(verge);
@@ -86,10 +94,11 @@ fn test_draft() {
assert_eq!(draft.draft().enable_auto_launch, Some(true));
assert_eq!(draft.draft().enable_tun_mode, Some(false));
let mut d = draft.draft();
d.enable_auto_launch = Some(false);
d.enable_tun_mode = Some(true);
drop(d);
{
let mut d = draft.draft();
d.enable_auto_launch = Some(false);
d.enable_tun_mode = Some(true);
}
assert_eq!(draft.data().enable_auto_launch, Some(true));
assert_eq!(draft.data().enable_tun_mode, Some(false));
@@ -109,18 +118,17 @@ fn test_draft() {
assert_eq!(draft.draft().enable_auto_launch, Some(false));
assert_eq!(draft.draft().enable_tun_mode, Some(true));
let mut d = draft.draft();
d.enable_auto_launch = Some(true);
drop(d);
{
let mut d = draft.draft();
d.enable_auto_launch = Some(true);
}
assert_eq!(draft.data().enable_auto_launch, Some(false));
assert_eq!(draft.draft().enable_auto_launch, Some(true));
assert!(draft.discard().is_some());
assert_eq!(draft.data().enable_auto_launch, Some(false));
assert!(draft.discard().is_none());
assert_eq!(draft.draft().enable_auto_launch, Some(false));