Hacker News new | ask | show | jobs
by atombender 143 days ago
I've made a tiny SwiftUI app. It was really difficult to figure out the memory leaks. In fact, I have leaks that I still haven't been able to find. For some reason the heap is fine, but the app continues to allocate virtual memory.

I've thrown Claude and Gemini at the app to try to analyze the code, had them use vmmap and Instruments, asked them run all of the code in a loop to reproduce the leakage — and still it leaks, slowly, tens of megabytes per day.

I'm sure it's something simple starting me in the face. But the fact remains that Swift's sort-of-automatic-but-not-quite memory model still makes it much harder to reason about memory than Rust or even Go.

10 comments

I agree, but I think that it's difficult to spot memory leaks in SwiftUI because it's such a high-level abstraction framework. When working with the Cocoa and Cocoa Touch libraries, it's so much easier to find.

And of course, Apple's UI frameworks != Swift the language itself.

hunting dangling references in a reference counted system is like that.... that's all I can guess is going on here. Good hunting! I wonder if there's a resource debugger? So far when I have really had to look, xcode was suffiicent... but there's likely better out there for finding this kind of thing.
I experienced a similar problem, and upon further investigation, I discovered that it occurred in the parts of the code where Swift and Objective-C are bridged. The problem seemed to stem from either the bridging or an issue within the Objective-C code itself
Perhaps try again and analyze for reference cycles between objects. I agree that ARC has painful subtleties. It existed prior to Swift, being introduced in Objective-C, and is definitely not a perfect memory model.
Personally I avoid using SwiftUI except in bite size chunks like collection view cells. It’s great for that kind of use case but doesn’t scale up well.

I wasn’t of the mind that AppKit/UIKit really needed replacing in the first place, though…

Sorry, I did mean AppKit here!
I'm sorry but what exactly are you doing? This is the first time I've ever heard any of this type of reasoning, and well, the fact that you're using AI makes me think you have no clue what you're actually talking about.

If its a reference cycle, instruments will find it. If it is a leak, instruments will find it. However, you seem to be worried about an implementation detail on how you get memory from your CPU which the mach kernel handles for you, and is something you don't quite grasp.

please don't reply with "I asked stupid generator", seriously, what is the actual issue you have?

They said they made a "small swiftUI" app that leaks memory. From their shared link there is no SwiftUI at all. No clue....
The memory management is almost broken. They decided not crashing was better than mashing memory.
Memory management in Swift is almost broken? How so? This is a fascinating assertion, and I’d love to learn more.
- it adds locking to almost every line of code using classes - anytime you start holding complex references to classes you get cycles which will not be released - it’s extremely hard to debug. You have to capture memgraphs at runtime and track dependencies - it coexists with old systems like auto release pools so resources are still not released when all references go away

Try to implement a linked list in swift and you’ll get a sense of how absurd this is. And remember linked lists are a special case of graphs.

What's the issue if it allocates virtual memory?
Having my app consume 300GB of virtual memory after running for a week is not ideal.
Is it actually resident or is it just mapped but unused?
It does not count under private memory, so I assume mapped but unused. The last time I asked Claude, it said confidently it was a bug in Swift's networking stack, which I doubt.
That’s the great thing about indiscriminately scraping the internet for knowledge.

I’ll bet Claude was channeling some Reddit guru dripping with swagger born from knowing their understanding of coding is far more advanced than most big-shots in the field— especially impressive because they only wandered into /r/LearnProgramming for the first time several months prior.

This guru's comment probably started with "I'll bet" too.
Mapped but unused memory is imaginary (at least, on modern UNIX systems). It's not actually using any physical RAM.
That is true, but I don't see other applications consuming ever-increasing amounts of virtual memory, so to me it suggests a bug.
Well, depends. Not always zero but in a good implementation not more than a few bytes per allocation, at most (if not zero).
Swift does not really have a networking stack
I've been out of the feature factory loop for a little while, but something tells me reviewing PRs is more entertaining these days.
Is it something you can share the code to?
Sure! It's open source: https://github.com/atombender/cistern.
Awesome, can you also grab a memgraph or something when it’s leaked a bunch of memory (and maybe put it in a GitHub issue)? I can try it but I don’t really use CircleCI so I’m not confident I can reproduce the issue.
There's no valgrind equivalent, I guess?

I mean, even if valgrind ran on MacOS, it may still not give anything meaningful because the debug symbols are probably not going to be the same as that generated by GCC, and even if they were the same, there's still gonna be a bunch of symbols "missing" because of internal swift name-mangling, and even if that wasn't the case, the emitted code might just not be ABI compatible with C anyway.

I'm working on Valgrind on macOS, integrating Louis Brunner's work and trying to add a few more fixes. In 2025 support for macOS Intel 10.14, 10.15 11 and 12 was added. Intel macOS 13 is a bit harder of a nut to crack. And I have lots of issues with ARM, particularly building and testing on anything older that macOS 15.

Swift name-mangling will be an issue. Valgrind's name demangler comes from GNU binutils libiberty which does not support Swift AFAIK.

The Instruments suite, plus sanitizers like ASan, is basically the valgrind equivalent on macOS. It’s not exactly the same, but it comes close.