@@ -13,7 +13,7 @@ use std::{
collections::BinaryHeap,
fmt, iter,
ops::{ControlFlow, Deref, DerefMut, Range},
- sync::Arc,
+ sync::{Arc, LazyLock},
time::{Duration, Instant},
};
use streaming_iterator::StreamingIterator;
@@ -40,6 +40,27 @@ pub struct SyntaxSnapshot {
update_count: usize,
}
+// Dropping deep treesitter Trees can be quite slow due to deallocating lots of memory.
+// To avoid blocking the main thread, we offload the drop operation to a background thread.
+impl Drop for SyntaxSnapshot {
+ fn drop(&mut self) {
+ static DROP_TX: LazyLock<std::sync::mpsc::Sender<SumTree<SyntaxLayerEntry>>> =
+ LazyLock::new(|| {
+ let (tx, rx) = std::sync::mpsc::channel();
+ std::thread::Builder::new()
+ .name("SyntaxSnapshot::drop".into())
+ .spawn(move || while let Ok(_) = rx.recv() {})
+ .expect("failed to spawn drop thread");
+ tx
+ });
+ // This does allocate a new Arc, but it's cheap and avoids blocking the main thread without needing to use an `Option` or `MaybeUninit`.
+ let _ = DROP_TX.send(std::mem::replace(
+ &mut self.layers,
+ SumTree::from_summary(Default::default()),
+ ));
+ }
+}
+
#[derive(Default)]
pub struct SyntaxMapCaptures<'a> {
layers: Vec<SyntaxMapCapturesLayer<'a>>,