Skip to content

Commit b89ff2d

Browse files
add GC docs
1 parent 895a981 commit b89ff2d

File tree

5 files changed

+210
-2
lines changed

5 files changed

+210
-2
lines changed

doc/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ generate_markdown("NEWS")
161161
Manual = [
162162
"manual/getting-started.md",
163163
"manual/installation.md",
164+
"manual/memory-management.md",
164165
"manual/variables.md",
165166
"manual/integers-and-floating-point-numbers.md",
166167
"manual/mathematical-operations.md",

doc/src/manual/command-line-interface.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ The following is a complete list of command-line switches available when launchi
180180
|`-m`, `--module <Package> [args]` |Run entry point of `Package` (`@main` function) with `args'|
181181
|`-L`, `--load <file>` |Load `<file>` immediately on all processors|
182182
|`-t`, `--threads {auto\|N[,auto\|M]}` |Enable N[+M] threads; N threads are assigned to the `default` threadpool, and if M is specified, M threads are assigned to the `interactive` threadpool; `auto` tries to infer a useful default number of threads to use but the exact behavior might change in the future. Currently sets N to the number of CPUs assigned to this Julia process based on the OS-specific affinity assignment interface if supported (Linux and Windows) or to the number of CPU threads if not supported (MacOS) or if process affinity is not configured, and sets M to 1.|
183-
| `--gcthreads=N[,M]` |Use N threads for the mark phase of GC and M (0 or 1) threads for the concurrent sweeping phase of GC. N is set to the number of compute threads and M is set to 0 if unspecified.|
183+
| `--gcthreads=N[,M]` |Use N threads for the mark phase of GC and M (0 or 1) threads for the concurrent sweeping phase of GC. N is set to the number of compute threads and M is set to 0 if unspecified. See [Memory Management and Garbage Collection](@ref man-memory-management) for more details.|
184184
|`-p`, `--procs {N\|auto}` |Integer value N launches N additional local worker processes; `auto` launches as many workers as the number of local CPU threads (logical cores)|
185185
|`--machine-file <file>` |Run processes on hosts listed in `<file>`|
186186
|`-i`, `--interactive` |Interactive mode; REPL runs and `isinteractive()` is true|
@@ -206,7 +206,7 @@ The following is a complete list of command-line switches available when launchi
206206
|`--track-allocation=@<path>` |Count bytes but only in files that fall under the given file path/directory. The `@` prefix is required to select this option. A `@` with no path will track the current directory.|
207207
|`--task-metrics={yes\|no*}` |Enable the collection of per-task metrics|
208208
|`--bug-report=KIND` |Launch a bug report session. It can be used to start a REPL, run a script, or evaluate expressions. It first tries to use BugReporting.jl installed in current environment and falls back to the latest compatible BugReporting.jl if not. For more information, see `--bug-report=help`.|
209-
|`--heap-size-hint=<size>` |Forces garbage collection if memory usage is higher than the given value. The value may be specified as a number of bytes, optionally in units of KB, MB, GB, or TB, or as a percentage of physical memory with %.|
209+
|`--heap-size-hint=<size>` |Forces garbage collection if memory usage is higher than the given value. The value may be specified as a number of bytes, optionally in units of KB, MB, GB, or TB, or as a percentage of physical memory with %. See [Memory Management and Garbage Collection](@ref man-memory-management) for more details.|
210210
|`--compile={yes*\|no\|all\|min}` |Enable or disable JIT compiler, or request exhaustive or minimal compilation|
211211
|`--output-o <name>` |Generate an object file (including system image data)|
212212
|`--output-ji <name>` |Generate a system image data file (.ji)|
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# [Memory Management and Garbage Collection](@id man-memory-management)
2+
3+
Julia uses automatic memory management through its built-in garbage collector (GC). This section provides an overview of how Julia manages memory and how you can configure and optimize memory usage for your applications.
4+
5+
## [Garbage Collection Overview](@id man-gc-overview)
6+
7+
Julia features a garbage collector with the following characteristics:
8+
9+
* **Non-moving**: Objects are not relocated in memory during garbage collection
10+
* **Generational**: Younger objects are collected more frequently than older ones
11+
* **Parallel and partially concurrent**: The GC can use multiple threads and run concurrently with your program
12+
* **Mostly precise**: The GC accurately identifies object references with minimal conservative scanning
13+
14+
The garbage collector automatically reclaims memory used by objects that are no longer reachable from your program, freeing you from manual memory management in most cases.
15+
16+
## [Memory Architecture](@id man-memory-architecture)
17+
18+
Julia uses a two-tier allocation strategy:
19+
20+
* **Small objects** (≤ 2032 bytes): Allocated using a fast per-thread pool allocator
21+
* **Large objects** (> 2032 bytes): Allocated directly through the system's `malloc`
22+
23+
This hybrid approach optimizes for both allocation speed and memory efficiency, with the pool allocator providing fast allocation for the many small objects typical in Julia programs.
24+
25+
## [System Memory Requirements](@id man-system-memory)
26+
27+
### Swap Space
28+
29+
Julia's garbage collector is designed with the expectation that your system has adequate swap space configured. The GC uses heuristics that assume it can allocate memory beyond physical RAM when needed, relying on the operating system's virtual memory management.
30+
31+
If your system has limited or no swap space, you may experience out-of-memory errors during garbage collection. In such cases, you can use the `--heap-size-hint` option to limit Julia's memory usage.
32+
33+
### Memory Hints
34+
35+
You can provide a hint to Julia about the maximum amount of memory to use:
36+
37+
```bash
38+
julia --heap-size-hint=4G # Limit heap to ~4GB
39+
julia --heap-size-hint=50% # Use up to 50% of physical memory
40+
```
41+
42+
The `--heap-size-hint` option tells the garbage collector to trigger collection more aggressively when approaching the specified limit. This is particularly useful in:
43+
44+
* Containers with memory limits
45+
* Systems without swap space
46+
* Shared systems where you want to limit Julia's memory footprint
47+
48+
You can also set this via the `JULIA_HEAP_SIZE_HINT` environment variable:
49+
50+
```bash
51+
export JULIA_HEAP_SIZE_HINT=2G
52+
julia
53+
```
54+
55+
## [Multithreaded Garbage Collection](@id man-gc-multithreading)
56+
57+
Julia's garbage collector can leverage multiple threads to improve performance on multi-core systems.
58+
59+
### GC Thread Configuration
60+
61+
By default, Julia uses multiple threads for garbage collection:
62+
63+
* **Mark threads**: Used during the mark phase to trace object references (default: same as compute threads (thread 1 is shared))
64+
* **Sweep threads**: Used for concurrent sweeping of freed memory (default: 0, disabled)
65+
66+
You can configure GC threading using:
67+
68+
```bash
69+
julia --gcthreads=4,1 # 4 mark threads, 1 sweep thread
70+
julia --gcthreads=8 # 8 mark threads, 0 sweep threads
71+
```
72+
73+
Or via environment variable:
74+
75+
```bash
76+
export JULIA_NUM_GC_THREADS=4,1
77+
julia
78+
```
79+
80+
### Recommendations
81+
82+
For compute-intensive workloads:
83+
84+
* Use multiple mark threads (the default configuration is usually appropriate)
85+
* Consider enabling concurrent sweeping with 1 sweep thread for allocation-heavy workloads
86+
87+
For memory-intensive workloads:
88+
89+
* Enable concurrent sweeping to reduce GC pauses
90+
* Monitor GC time using `@time` and adjust thread counts accordingly
91+
92+
## [Monitoring and Debugging](@id man-gc-monitoring)
93+
94+
### Basic Memory Monitoring
95+
96+
Use the `@time` macro to see memory allocation and GC overhead:
97+
98+
```julia
99+
julia> @time some_computation()
100+
2.123456 seconds (1.50 M allocations: 58.725 MiB, 17.17% gc time)
101+
```
102+
103+
This shows:
104+
105+
* Total execution time
106+
* Number of allocations
107+
* Memory allocated
108+
* Percentage of time spent in garbage collection
109+
110+
### GC Logging
111+
112+
Enable detailed GC logging to understand collection patterns:
113+
114+
```julia
115+
julia> GC.enable_logging(true)
116+
julia> # Run your code
117+
julia> GC.enable_logging(false)
118+
```
119+
120+
This logs each garbage collection event with timing and memory statistics.
121+
122+
### Manual GC Control
123+
124+
While generally not recommended, you can manually trigger garbage collection:
125+
126+
```julia
127+
GC.gc() # Force a garbage collection
128+
GC.enable(false) # Disable automatic GC (use with caution!)
129+
GC.enable(true) # Re-enable automatic GC
130+
```
131+
132+
**Warning**: Disabling GC can lead to memory exhaustion. Only use this for specific performance measurements or debugging.
133+
134+
## [Performance Considerations](@id man-gc-performance)
135+
136+
### Reducing Allocations
137+
138+
The best way to minimize GC impact is to reduce unnecessary allocations:
139+
140+
* Use in-place operations when possible (e.g., `x .+= y` instead of `x = x + y`)
141+
* Pre-allocate arrays and reuse them
142+
* Avoid creating temporary objects in tight loops
143+
* Consider using `StaticArrays.jl` for small, fixed-size arrays
144+
145+
### Memory-Efficient Patterns
146+
147+
* Use `Vector{Float64}` instead of `Vector{Any}` when possible
148+
* Avoid global variables that change type
149+
* Use `const` for global constants
150+
* Consider memory pools for frequently allocated/freed objects
151+
152+
### Profiling Memory Usage
153+
154+
For detailed guidance on profiling memory allocations and identifying performance bottlenecks, see the [Profiling](@ref man-profiling) section.
155+
156+
## [Advanced Configuration](@id man-gc-advanced)
157+
158+
### Environment Variables
159+
160+
Additional GC-related environment variables:
161+
162+
* `JULIA_GC_WAIT_FOR_DEBUGGER`: Pause for debugger attachment during GC (debug builds only)
163+
* `JULIA_PROFILE_PEEK_HEAP_SNAPSHOT`: Enable heap snapshot collection during profiling
164+
165+
### Integration with System Memory Management
166+
167+
Julia works best when:
168+
169+
* The system has adequate swap space (recommended: 2x physical RAM)
170+
* Virtual memory is properly configured
171+
* Other processes leave sufficient memory available
172+
* Container memory limits are set appropriately with `--heap-size-hint`
173+
174+
## [Troubleshooting Memory Issues](@id man-gc-troubleshooting)
175+
176+
### Out of Memory Errors
177+
178+
If you encounter out-of-memory errors:
179+
180+
1. **Check system memory**: Ensure adequate RAM and swap space
181+
2. **Use heap size hints**: Set `--heap-size-hint` to limit memory usage
182+
3. **Profile allocations**: Identify and reduce unnecessary allocations
183+
4. **Consider chunking**: Process data in smaller chunks for large datasets
184+
185+
### High GC Overhead
186+
187+
If garbage collection is taking too much time:
188+
189+
1. **Reduce allocation rate**: Focus on algorithmic improvements
190+
2. **Adjust GC threads**: Experiment with different `--gcthreads` settings
191+
3. **Use concurrent sweeping**: Enable background sweeping with `--gcthreads=N,1`
192+
4. **Profile memory patterns**: Identify allocation hotspots and optimize them
193+
194+
### Memory Leaks
195+
196+
While Julia's GC prevents most memory leaks, issues can still occur:
197+
198+
* **Global references**: Avoid holding references to large objects in global variables
199+
* **Closures**: Be careful with closures that capture large amounts of data
200+
* **C interop**: Ensure proper cleanup when interfacing with C libraries
201+
* **Circular references**: While handled by the GC, they can delay collection
202+
203+
For more detailed information about Julia's garbage collector internals, see the Garbage Collection section in the Developer Documentation.

doc/src/manual/multi-threading.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ of compute worker threads or configured by either the `--gcthreads` command line
9191
!!! compat "Julia 1.10"
9292
The `--gcthreads` command line argument requires at least Julia 1.10.
9393

94+
For more details about garbage collection configuration and performance tuning, see [Memory Management and Garbage Collection](@ref man-memory-management).
95+
9496
## [Threadpools](@id man-threadpools)
9597

9698
When a program's threads are busy with many tasks to run, tasks may experience

doc/src/manual/performance-tips.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ Consequently, in addition to the allocation itself, it's very likely
114114
that the code generated for your function is far from optimal. Take such indications seriously
115115
and follow the advice below.
116116

117+
For more information about memory management and garbage collection in Julia, see [Memory Management and Garbage Collection](@ref man-memory-management).
118+
117119
In this particular case, the memory allocation is due to the usage of a type-unstable global variable `x`, so if we instead pass `x` as an argument to the function it no longer allocates memory
118120
(the remaining allocation reported below is due to running the `@time` macro in global scope)
119121
and is significantly faster after the first call:

0 commit comments

Comments
 (0)