Skip to content

Commit b9ca066

Browse files
authored
Reduce memory usage when using many pages with examples (#2662)
1 parent 160521c commit b9ca066

File tree

5 files changed

+67
-0
lines changed

5 files changed

+67
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## Changed
99

1010
* Now the cursor remain focused on search box even after selecting the filter. ([#2410])
11+
* The "sandbox" modules used for running the code (doctests, examples) are now cleared after a page has been processed, allowing the garbage collector to reclaim memory and therefore reducing memory usage. ([#2640], [#2662])
1112

1213
## Fixed
1314

@@ -1985,6 +1986,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19851986
[#2624]: https://github.com/JuliaDocs/Documenter.jl/issues/2624
19861987
[#2629]: https://github.com/JuliaDocs/Documenter.jl/issues/2629
19871988
[#2636]: https://github.com/JuliaDocs/Documenter.jl/issues/2636
1989+
[#2640]: https://github.com/JuliaDocs/Documenter.jl/issues/2640
19881990
[#2642]: https://github.com/JuliaDocs/Documenter.jl/issues/2642
19891991
[#2646]: https://github.com/JuliaDocs/Documenter.jl/issues/2646
19901992
[#2648]: https://github.com/JuliaDocs/Documenter.jl/issues/2648
@@ -1993,6 +1995,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19931995
[#2652]: https://github.com/JuliaDocs/Documenter.jl/issues/2652
19941996
[#2656]: https://github.com/JuliaDocs/Documenter.jl/issues/2656
19951997
[#2658]: https://github.com/JuliaDocs/Documenter.jl/issues/2658
1998+
[#2662]: https://github.com/JuliaDocs/Documenter.jl/issues/2662
19961999
[JuliaLang/julia#36953]: https://github.com/JuliaLang/julia/issues/36953
19972000
[JuliaLang/julia#38054]: https://github.com/JuliaLang/julia/issues/38054
19982001
[JuliaLang/julia#39841]: https://github.com/JuliaLang/julia/issues/39841

src/expander_pipeline.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# Defines node "expanders" that transform nodes from the parsed markdown files.
22

3+
# helper for "cleaning up" content of modules to enable garbage collection.
4+
# See also <https://github.com/JuliaDocs/Documenter.jl/issues/2640>.
5+
function clear_module!(M::Module)
6+
# we need `invokelatest` here for Julia >= 1.12 (or 1.13?)
7+
for name in Base.invokelatest(names, M, all = true)
8+
if !isconst(M, name)
9+
@eval M $name = $nothing
10+
end
11+
end
12+
return
13+
end
14+
15+
function clear_modules!(d::Dict{Symbol, Any})
16+
for (k, v) in d
17+
startswith(String(k), "__atexample__") || continue
18+
v isa Module && clear_module!(v)
19+
end
20+
GC.gc()
21+
return
22+
end
23+
324
function expand(doc::Documenter.Document)
425
priority_pages = filter(doc.user.expandfirst) do src
526
if src in keys(doc.blueprint.pages)
@@ -23,6 +44,7 @@ function expand(doc::Documenter.Document)
2344
expand_recursively(node, page, doc)
2445
end
2546
pagecheck(page)
47+
clear_modules!(page.globals.meta)
2648
end
2749
return
2850
end

test/clear_module/src/index.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Testing
2+
3+
We set up some test code and create an object with a finalizer.
4+
5+
```@setup
6+
@eval Main finalizer_count = [0]
7+
8+
mutable struct MyMutableStruct
9+
bar
10+
function MyMutableStruct(bar)
11+
x = new(bar)
12+
finalizer(x) do y
13+
Main.finalizer_count[1] += 1
14+
end
15+
end
16+
end
17+
18+
a = MyMutableStruct(1)
19+
```
20+
21+
Once Documenter is finished processing this page, it should remove the
22+
reference to the object `a` and a subsequent garbage collection should free
23+
it, which we can later test by observing the value of `Main.finalizer_count`.

test/clear_module/tests.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Documenter
2+
using Test
3+
4+
const pages = [
5+
"Home" => "index.md",
6+
]
7+
8+
makedocs(sitename = "Test", pages = pages, doctest = true)
9+
10+
@testset "clear_modules!" begin
11+
# force a full GC
12+
GC.gc(true)
13+
# check that the finalizer was run
14+
@test Main.finalizer_count[1] == 1
15+
end

test/runtests.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ end
9494
@info "Building workdir/tests.jl"
9595
@quietly include("workdir/tests.jl")
9696

97+
# A simple build verifying that sandbox modules are cleared at the end of each page
98+
@info "Building clear_module/tests.jl"
99+
@quietly include("clear_module/tests.jl")
100+
97101
# Passing a writer positionally (https://github.com/JuliaDocs/Documenter.jl/issues/1046)
98102
@test_throws MethodError makedocs(sitename = "", HTML())
99103

0 commit comments

Comments
 (0)