Fix: memory leak on listeners for elements (#2244)
* Fix: memory leak on listeners for elements * Recycle in manuallydrop --------- Co-authored-by: Evan Almloff <evanalmloff@gmail.com>
This commit is contained in:
1 parent
6f3c5518ca
commit
44fe2defc2
3 files changed
+27
-2
No files matched your search
Generated
+1
@@ -2453,6 +2453,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tracing",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -142,6 +142,29 @@ impl Clone for VNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for VNode {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// FIXME:
|
||||||
|
// TODO:
|
||||||
|
//
|
||||||
|
// We have to add this drop *here* becase we can't add a drop impl to AttributeValue and
|
||||||
|
// keep semver compatibility. Adding a drop impl means you can't destructure the value, which
|
||||||
|
// we need to do for enums.
|
||||||
|
//
|
||||||
|
// if dropping this will drop the last vnode (rc count is 1), then we need to drop the listeners
|
||||||
|
// in this template
|
||||||
|
if Rc::strong_count(&self.vnode) == 1 {
|
||||||
|
for attrs in self.vnode.dynamic_attrs.iter() {
|
||||||
|
for attr in attrs.iter() {
|
||||||
|
if let AttributeValue::Listener(listener) = &attr.value {
|
||||||
|
listener.callback.manually_drop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for VNode {
|
impl PartialEq for VNode {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
Rc::ptr_eq(&self.vnode, &other.vnode)
|
Rc::ptr_eq(&self.vnode, &other.vnode)
|
||||||
@@ -714,14 +737,14 @@ impl AttributeValue {
|
|||||||
///
|
///
|
||||||
/// The callback must be confined to the lifetime of the ScopeState
|
/// The callback must be confined to the lifetime of the ScopeState
|
||||||
pub fn listener<T: 'static>(mut callback: impl FnMut(Event<T>) + 'static) -> AttributeValue {
|
pub fn listener<T: 'static>(mut callback: impl FnMut(Event<T>) + 'static) -> AttributeValue {
|
||||||
|
// TODO: maybe don't use the copy-variant of EventHandler here?
|
||||||
|
// Maybe, create an Owned variant so we are less likely to run into leaks
|
||||||
AttributeValue::Listener(EventHandler::new(move |event: Event<dyn Any>| {
|
AttributeValue::Listener(EventHandler::new(move |event: Event<dyn Any>| {
|
||||||
let data = event.data.downcast::<T>().unwrap();
|
let data = event.data.downcast::<T>().unwrap();
|
||||||
// if let Ok(data) = event.data.downcast::<T>() {
|
|
||||||
callback(Event {
|
callback(Event {
|
||||||
propagates: event.propagates,
|
propagates: event.propagates,
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
// }
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ impl<T, S: Storage<T>> GenerationalBox<T, S> {
|
|||||||
/// Drop the value out of the generational box and invalidate the generational box. This will return the value if the value was taken.
|
/// Drop the value out of the generational box and invalidate the generational box. This will return the value if the value was taken.
|
||||||
pub fn manually_drop(&self) -> Option<T> {
|
pub fn manually_drop(&self) -> Option<T> {
|
||||||
if self.validate() {
|
if self.validate() {
|
||||||
|
<S as AnyStorage>::recycle(&self.raw);
|
||||||
Storage::take(&self.raw.0.data)
|
Storage::take(&self.raw.0.data)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|||||||
Reference in new issue
Block a user