Skip to content

directly deallocates the nodes instead of traversing every element when BTreemap dropping - #162931

Open
ywxt wants to merge 1 commit into
rust-lang:mainfrom
ywxt:btree_map_drop
Open

ywxt wants to merge 1 commit into
rust-lang:mainfrom
ywxt:btree_map_drop

Conversation

@ywxt

@ywxt ywxt commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

When BTreeMap is dropping, it currently turns the tree into an iterator and traverses the kvs, updating the LazyLeafRange after each element is dropped. This is unnecessary during destruction. We can instead traverse the tree node by node and drop the kvs directly from each node.

Results on aarch64:

  • btree::map
benchmark baseline without drop change with drop change pp diff (with − without)
clone_fat_val_100 10849.14 7433.38 -31.5% 7573.66 -30.2% +1.3pp
clone_fat_val_100_and_clear 11021.05 7606.91 -31.0% 7769.49 -29.5% +1.5pp
clone_fat_val_100_and_drain_all 57652.20 55026.07 -4.6% 55495.20 -3.7% +0.8pp
clone_fat_val_100_and_drain_half 27258.25 23993.80 -12.0% 24005.43 -11.9% +0.0pp
clone_fat_val_100_and_into_iter 15149.81 12289.52 -18.9% 12401.29 -18.1% +0.7pp
clone_fat_val_100_and_pop_all 56717.62 54045.12 -4.7% 54643.59 -3.7% +1.1pp
clone_fat_val_100_and_remove_all 64333.00 61907.57 -3.8% 62039.79 -3.6% +0.2pp
clone_fat_val_100_and_remove_half 28440.43 25290.79 -11.1% 25634.00 -9.9% +1.2pp
clone_slim_100 1978.26 687.38 -65.3% 798.38 -59.6% +5.6pp
clone_slim_100_and_clear 1908.35 687.58 -64.0% 796.25 -58.3% +5.7pp
clone_slim_100_and_drain_all 3983.43 4244.24 +6.5% 4123.55 +3.5% -3.0pp
clone_slim_100_and_drain_half 4241.43 3551.33 -16.3% 3624.14 -14.6% +1.7pp
clone_slim_100_and_into_iter 1805.39 1753.37 -2.9% 1840.42 +1.9% +4.8pp
clone_slim_100_and_pop_all 3243.54 3247.17 +0.1% 3321.00 +2.4% +2.3pp
clone_slim_100_and_remove_all 5203.97 5176.58 -0.5% 5282.19 +1.5% +2.0pp
clone_slim_100_and_remove_half 2399.04 1818.85 -24.2% 1929.16 -19.6% +4.6pp
clone_slim_10k 205051.50 74942.50 -63.5% 83515.00 -59.3% +4.2pp
clone_slim_10k_and_clear 197575.50 74994.75 -62.0% 82934.71 -58.0% +4.0pp
clone_slim_10k_and_drain_all 425268.00 424679.50 -0.1% 432531.75 +1.7% +1.8pp
clone_slim_10k_and_drain_half 408679.00 358468.67 -12.3% 366904.50 -10.2% +2.1pp
clone_slim_10k_and_into_iter 184573.50 180805.00 -2.0% 188245.25 +2.0% +4.0pp
clone_slim_10k_and_pop_all 369476.00 370334.50 +0.2% 378684.50 +2.5% +2.3pp
clone_slim_10k_and_remove_all 582219.44 581719.69 -0.1% 590480.50 +1.4% +1.5pp
clone_slim_10k_and_remove_half 424686.50 373048.00 -12.2% 382718.00 -9.9% +2.3pp
from_iter_rand_100 1832.99 1086.70 -40.7% 1194.53 -34.8% +5.9pp
from_iter_rand_10_000 304447.00 231011.33 -24.1% 234360.00 -23.0% +1.1pp
from_iter_seq_100 2045.17 750.12 -63.3% 896.15 -56.2% +7.1pp
from_iter_seq_10_000 211268.33 80514.29 -61.9% 85877.83 -59.4% +2.5pp
  • btree::set
benchmark baseline without drop change with drop change pp diff (with − without)
clone_100 1913.17 605.95 -68.3% 745.54 -61.0% +7.3pp
clone_100_and_clear 1813.35 608.09 -66.5% 743.81 -59.0% +7.5pp
clone_100_and_drain_all 3960.52 3965.28 +0.1% 4088.26 +3.2% +3.1pp
clone_100_and_drain_half 4045.63 3408.90 -15.7% 3559.55 -12.0% +3.7pp
clone_100_and_into_iter 1676.32 1600.11 -4.5% 1721.67 +2.7% +7.3pp
clone_100_and_pop_all 2582.26 2562.19 -0.8% 2686.39 +4.0% +4.8pp
clone_100_and_remove_all 4574.45 4520.84 -1.2% 4671.70 +2.1% +3.3pp
clone_100_and_remove_half 2107.02 1533.22 -27.2% 1673.91 -20.6% +6.7pp
clone_10k 192719.50 65933.38 -65.8% 75038.88 -61.1% +4.7pp
clone_10k_and_clear 184669.60 66101.87 -64.2% 75375.25 -59.2% +5.0pp
clone_10k_and_drain_all 418832.00 417920.00 -0.2% 424436.00 +1.3% +1.6pp
clone_10k_and_drain_half 400446.00 348149.50 -13.1% 351997.00 -12.1% +1.0pp
clone_10k_and_into_iter 170359.60 163481.80 -4.0% 165757.25 -2.7% +1.3pp
clone_10k_and_pop_all 306021.67 307441.67 +0.5% 307585.00 +0.5% +0.0pp
clone_10k_and_remove_all 510750.88 511582.56 +0.2% 512938.25 +0.4% +0.3pp
clone_10k_and_remove_half 385672.00 337072.33 -12.6% 341705.50 -11.4% +1.2pp

r? @Amanieu

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 18, 2026
@rustbot rustbot added the T-libs Relevant to the library team, which will review and decide on the PR/issue. label Sep 18, 2026
Comment thread library/alloc/src/collections/btree/navigate.rs Outdated
Comment thread library/alloc/src/collections/btree/map.rs Outdated
@ywxt ywxt changed the title directly drop the subtree instead of traversing every element when BTreemap dropping directly deallocates the nodes instead of traversing every element when BTreemap dropping Sep 22, 2026

@Abhirup0 Abhirup0 left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I walked through the postorder traversal logic and panic safety guards across drop_kvs and drop_tree. The cleanup order and unwinding guarantees look solid:

  • drop_kvs's inner guard drops any remaining elements in the active node if a destructor panics, while the outer guard in drop_tree ensures the remaining tree is traversed and deallocated without leaks.
  • Deallocating nodes in postorder right after their elements drop avoids all the LazyLeafRange tracking overhead and matches the benchmarks well.
  • The else branch in BTreeMap::drop properly handles dropping self.alloc when self.root is None.

Two minor non-blocking notes:

  1. In library/alloc/src/collections/btree/node.rs line 448, the safety comment in DropGuard::drop mentions idx < len, but the loop index is i.
  2. In library/alloc/src/collections/btree/node.rs line 438, drop_kvs could take &mut self instead of &self to better reflect that it mutates and invalidates the node's element storage.

Nice work addressing the earlier feedback!

View changes since this review

@rust-bors

rust-bors Bot commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

☔ The latest upstream changes (presumably #163379) made this pull request unmergeable. Please resolve the merge conflicts by rebasing.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants