You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Reformatted and added spaces before backticks to correct content alignment.
* Update memory-leaks-and-usage.md
Removed spacing for a numbered bullet set to remove formatting as a code block.
* Tidy up code formats
---------
Co-authored-by: Tim <[email protected]>
Copy file name to clipboardExpand all lines: documentation/server/guides/memory-leaks-and-usage.md
+41-19Lines changed: 41 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,36 +12,37 @@ It’s important to note, however, that a gradual increase in memory usage over
12
12
13
13
Debugging memory leaks in Swift on macOS and Linux environments can be done using different tools and techniques, each with distinct strengths and usability.
14
14
15
-
Basic troubleshooting steps include:
15
+
**Basic troubleshooting steps include:**
16
16
17
17
1. Using profiling tools, provided by the respective operating systems and development environments, to identify and analyze memory usage.
18
18
19
-
**For macOS**, [Memory Graph Debugger](https://developer.apple.com/documentation/xcode/gathering-information-about-memory-use#Inspect-the-debug-memory-graph) and this [Detect and diagnose memory issues](https://developer.apple.com/videos/play/wwdc2021/10180/) video are helpful. You can also use the [Xcode Instruments](https://help.apple.com/instruments/mac/10.0/#/dev022f987b) tool for various profiling instruments including the [Allocations instrument](https://developer.apple.com/documentation/xcode/gathering-information-about-memory-use#Profile-your-app-using-the-Allocations-instrument) to track memory allocation and deallocation in your Swift code.
19
+
**For macOS**, [Memory Graph Debugger](https://developer.apple.com/documentation/xcode/gathering-information-about-memory-use#Inspect-the-debug-memory-graph) and this [Detect and diagnose memory issues](https://developer.apple.com/videos/play/wwdc2021/10180/) video are helpful. You can also use the [Xcode Instruments](https://help.apple.com/instruments/mac/10.0/#/dev022f987b) tool for various profiling instruments including the [Allocations instrument](https://developer.apple.com/documentation/xcode/gathering-information-about-memory-use#Profile-your-app-using-the-Allocations-instrument) to track memory allocation and deallocation in your Swift code.
20
20
21
-
**For Linux**, you can use tools like [Valgrind](https://valgrind.org/) or [Heaptrack](https://github.com/KDE/heaptrack) to profile your application as shown in the examples below. Although these tools are primarily used for C/C++ code, they can also work with Swift.
21
+
**For Linux**, you can use tools like [Valgrind](https://valgrind.org/) or [Heaptrack](https://github.com/KDE/heaptrack) to profile your application as shown in the examples below. Although these tools are primarily used for C/C++ code, they can also work with Swift.
22
22
23
23
2. Reviewing code and identifying potential leaks to examine your code for any potential areas where memory leaks may occur. Common sources of leaks include retained references or unbalanced retain-release cycles, which rarely apply to Swift since it performs [automatic reference counting (ARC)](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/).
24
24
25
-
> Note: Memory leaks can occur in Swift if there are substantial reference cycles between objects that involve closures or if objects hold references to external resources that are not released properly. However, the likelihood of such issues is significantly reduced through the automatic memory management's ability to add and remove references, making sources of leaks like retained references and unbalanced retain-release cycles less common in Swift code.
25
+
**Note:** Memory leaks can occur in Swift if there are substantial reference cycles between objects that involve closures or if objects hold references to external resources that are not released properly. However, the likelihood of such issues is significantly reduced through the automatic memory management's ability to add and remove references, making sources of leaks like retained references and unbalanced retain-release cycles less common in Swift code.
26
26
27
27
3. Enabling debug memory allocation features allows you to get additional information about objects and their memory allocations.
28
28
29
-
**On macOS**, you can enable Zombie Objects using Xcode or use [MallocStackLogging](https://developer.apple.com/videos/play/wwdc2022/10106/) to detect over-released or accessed deallocated objects.
29
+
**On macOS**, you can enable Zombie Objects using Xcode or use [MallocStackLogging](https://developer.apple.com/videos/play/wwdc2022/10106/) to detect over-released or accessed deallocated objects.
30
30
31
-
To enable Zombie Objects:
32
-
1. Open your Xcode project.
33
-
2. Go to the **Edit Scheme** menu by clicking on the scheme dropdown in the toolbar.
34
-
3. In the scheme editor window, select the **Run** tab.
35
-
4. Choose the **Diagnostics** tab.
36
-
5. Under **Memory Management**, check the box next to **Enable Zombie Objects**.
31
+
To enable Zombie Objects:
32
+
1. Open your Xcode project.
33
+
2. Go to the **Edit Scheme** menu by clicking on the scheme dropdown in the toolbar.
34
+
3. In the scheme editor window, select the **Run** tab.
35
+
4. Choose the **Diagnostics** tab.
36
+
5. Under **Memory Management**, check the box next to **Enable Zombie Objects**.
37
37
38
-
**On Linux**, Swift has built-in LeakSanitizer support that can be enabled using the `-sanitize=leak` compiler flag.
38
+
**On Linux**, Swift has built-in LeakSanitizer support that can be enabled using the `-sanitize=leak` compiler flag.
39
39
40
40
### Troubleshooting
41
41
42
42
This section aims to provide you with helpful server-side troubleshooting techniques to debug leaks and usage using **Valgrind**, **LeakSanitizer**, and **Heaptrack**.
43
43
44
-
The following **example program** leaks memory. We are using it as an *example only* to illustrate the various troubleshooting methods mentioned below.
44
+
The following **example program** leaks memory. We are using it as an *example only* to illustrate the various troubleshooting methods mentioned below.
Valgrind is an open-source framework for debugging and profiling Linux applications. It provides several tools, including Memcheck, which can detect memory leaks, invalid memory accesses, and other memory errors. Although Valgrind is primarily focused on C/C++ applications, it can also be used with Swift on Linux.
72
74
@@ -86,6 +88,7 @@ brew install valgrind
86
88
Valgrind should be successfully installed on your system using the system package manager.
87
89
88
90
5. Once you've compiled your program (in this case, a binary named `test`), run the following `valgrind` command to enable full leak checking:
1. Install Swift on your Linux system. You can download and install Swift from the [official website](https://swift.org/download/).
96
99
97
100
2. Install Valgrind on your Linux system by using your package manager. For example, if you are using Ubuntu, you can run the following command:
101
+
98
102
```
99
103
sudo apt-get install valgrind
100
104
```
101
105
102
106
3. Once Valgrind is installed, run the following command:
107
+
103
108
```
104
109
valgrind --leak-check=full swift run
105
110
```
@@ -139,6 +144,7 @@ The `valgrind` command analyzes the program for any memory leaks and shows the r
139
144
```
140
145
141
146
The following trace block (from above) indicates a memory leak.
147
+
142
148
```
143
149
==1== 32 bytes in 1 blocks are definitely lost in loss record 1 of 4
144
150
==1== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
@@ -152,6 +158,7 @@ The following trace block (from above) indicates a memory leak.
152
158
However, since Swift uses name mangling for function and symbol names, the stack traces may not be straightforward to understand.
153
159
154
160
To demangle the Swift symbols in the stack traces, run the `swift demangle` command:
161
+
155
162
```
156
163
swift demangle <mangled_symbol>
157
164
```
@@ -160,9 +167,10 @@ Replace `<mangled_symbol>` with the mangled symbol name shown in the stack trace
160
167
161
168
`swift demangle $s4test12MemoryLeakerCACycfC`
162
169
163
-
> Note: `swift demangle` is a Swift command line utility and should be available if you have the Swift toolchain installed.
170
+
**Note:**`swift demangle` is a Swift command line utility and should be available if you have the Swift toolchain installed.
164
171
165
172
The utility will demangle the symbol and display a human-readable version as follows:
173
+
166
174
```
167
175
==1== 32 bytes in 1 blocks are definitely lost in loss record 1 of 4
168
176
==1== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
@@ -190,16 +198,19 @@ Here are the steps:
190
198
191
199
1. Open a terminal session and navigate to your Swift package directory.
192
200
2. Set the `ASAN_OPTIONS` environment variable to enable AddressSanitizer and configure its behavior. You can do this by running the command:
201
+
193
202
```
194
203
export ASAN_OPTIONS=detect_leaks=1
195
204
```
196
205
197
206
3. Run `swift build` with the additional option to enable [Address Sanitizer](https://developer.apple.com/documentation/xcode/diagnosing-memory-thread-and-crash-issues-early):
207
+
198
208
```
199
209
swift build --sanitize=address
200
210
```
201
211
202
212
The build process will compile your code with AddressSanitizer enabled, which automatically looks for leaked memory blocks. If any memory leaks during the build are detected, it will output the information (similar to Valgrind) as shown in the example below:
@@ -213,31 +224,36 @@ Direct leak of 32 byte(s) in 1 object(s) allocated from:
213
224
214
225
SUMMARY: AddressSanitizer: 32 byte(s) leaked in 1 allocation(s).
215
226
```
227
+
216
228
Currently, the output doesn’t provide a human-readable representation of the function names because [LeakSanitizer doesn't symbolicate stack traces on Linux](https://github.com/apple/swift/issues/55046).
217
229
218
230
However, you can symbolicate it using `llvm-symbolizer` or `addr2line` if you have `binutils` installed.
219
231
220
232
To install `binutils` for Swift on a server running Linux, follow these steps:
221
233
1. Connect to your Swift server through SSH using a terminal.
222
234
2. Update the package lists by running the following command:
235
+
223
236
```
224
237
sudo apt update
225
238
```
226
239
227
240
3. Install `binutils` by running the following command:
241
+
228
242
```
229
243
sudo apt install binutils
230
244
```
231
245
232
246
4. This will install `binutils` and its related tools for working with binaries, object files, and libraries, which can be useful for developing and debugging Swift applications on Linux.
233
247
234
248
You can now run the following command to demangle the symbols in the stack traces:
249
+
235
250
```
236
251
# /tmp/test+0xc62ce
237
-
addr2line -e /tmp/test -a 0xc62ce -ipf | swift demangle
252
+
addr2line -e /tmp/test -a 0xc62ce -ipf | swift demangle
238
253
```
239
254
240
255
In this example, the allocation that leaked is coming from:
256
+
241
257
```
242
258
0x00000000000c62ce: test.myFunctionDoingTheAllocation() -> () at crtstuff.c:?
243
259
```
@@ -256,13 +272,15 @@ A GUI front-end analyzer `heaptrack_gui` is available in addition to command lin
256
272
257
273
Using a different example, here’s a short how-to using [Ubuntu](https://www.swift.org/download/) to analyze transient usage.
258
274
1. Install `heaptrack` by running this command:
275
+
259
276
```
260
277
sudo apt-get install heaptrack
261
278
```
262
279
263
280
2. Run the binary twice using `heaptrack`. The first run provides a baseline for `main`.
The output shows 673989 allocations in the `feature branch` version and 319347 in `main`, indicating a regression.
295
314
296
315
4. Run the following command to analyze the output as a diff from these runs using `heaptrack_print` and pipe it through `swift demangle` for readability:
316
+
297
317
```
298
318
heaptrack_print -T -d heaptrack.test_1000_autoReadGetAndSet.84341.gz heaptrack.test_1000_autoReadGetAndSet.84372.gz | swift demangle
299
319
```
300
320
301
-
> Note: `-T` outputs the temporary allocations, providing transient allocations and not leaks. If leaks are detected, remove `-T`.
321
+
**Note:**`-T` outputs the temporary allocations, providing transient allocations and not leaks. If leaks are detected, remove `-T`.
302
322
303
323
Scroll down to see the transient allocations (output may be long):
324
+
304
325
```
305
326
MOST TEMPORARY ALLOCATIONS
306
327
307740 temporary allocations of 290324 allocations in total (106.00%) from
@@ -339,6 +360,7 @@ swift_slowAlloc
339
360
```
340
361
341
362
Looking at the output above, we can see the extra transient allocations were due to extra debug printing and querying of environment variables as shown below:
In this example, the debug prints are only for testing and would be removed from the code before the branch is merged.
350
372
351
-
> Tip: Heaptrack can also be [installed on an RPM-based distribution](https://rhel.pkgs.org/8/epel-x86_64/heaptrack-1.2.0-7.el8.x86_64.rpm.html) to debug transient memory usage. You may need to consult the distribution's documentation for the specific repository setup steps. When Heaptrack is installed correctly, it should display its version and usage information.
373
+
**Tip:** Heaptrack can also be [installed on an RPM-based distribution](https://rhel.pkgs.org/8/epel-x86_64/heaptrack-1.2.0-7.el8.x86_64.rpm.html) to debug transient memory usage. You may need to consult the distribution's documentation for the specific repository setup steps. When Heaptrack is installed correctly, it should display its version and usage information.
0 commit comments