https://github.com/coenttb/swift-memory-allocation
A Swift library for memory allocation observability.
https://github.com/coenttb/swift-memory-allocation
allocation cross-platform leak-detection linux macos memory observability performance profiling server-side-swift swift testing
Last synced: 2 months ago
JSON representation
A Swift library for memory allocation observability.
- Host: GitHub
- URL: https://github.com/coenttb/swift-memory-allocation
- Owner: coenttb
- License: apache-2.0
- Created: 2025-11-18T09:49:50.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2025-11-18T11:11:43.000Z (3 months ago)
- Last Synced: 2025-11-18T11:26:28.626Z (3 months ago)
- Topics: allocation, cross-platform, leak-detection, linux, macos, memory, observability, performance, profiling, server-side-swift, swift, testing
- Language: Swift
- Homepage: https://coenttb.com
- Size: 38.1 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# swift-memory-allocation
[](https://github.com/coenttb/swift-memory-allocation/actions/workflows/ci.yml)

**Cross-platform memory allocation observability for Swift**
A focused library providing memory allocation tracking, leak detection, peak memory profiling, and allocation histograms across macOS and Linux.
## Features
- **Allocation Tracking** - Measure memory allocations in code blocks
- **Leak Detection** - Detect memory leaks by tracking net allocations
- **Peak Memory Tracking** - Monitor peak memory usage over time
- **Allocation Profiling** - Profile allocations with statistics and histograms
- **Cross-Platform** - Works on macOS and Linux with platform-optimized implementations
- **Thread-Safe** - All trackers are Sendable and safe for concurrent use
- **Zero Dependencies** - Pure Swift using only Darwin/Glibc platform primitives (no Foundation)
## Installation
Add `swift-memory-allocation` to your `Package.swift`:
```swift
dependencies: [
.package(url: "https://github.com/coenttb/swift-memory-allocation", from: "0.1.0")
]
```
Then add it to your target:
```swift
.target(
name: "YourTarget",
dependencies: [
.product(name: "MemoryAllocation", package: "swift-memory-allocation")
]
)
```
## Quick Start
### Basic Allocation Tracking
```swift
import MemoryAllocation
// Measure allocations in a code block
let (result, stats) = AllocationTracker.measure {
let array = Array(repeating: 0, count: 1000)
return array.count
}
print("Allocated \(stats.bytesAllocated) bytes")
print("Allocations: \(stats.allocations)")
print("Deallocations: \(stats.deallocations)")
```
### Leak Detection
```swift
let detector = LeakDetector()
// Your code here
var leaked: [[Int]] = []
for i in 0..<100 {
leaked.append(Array(repeating: i, count: 100))
}
if detector.hasLeaks() {
print("Warning: \(detector.netAllocations) leaked allocations")
print("Net bytes: \(detector.netBytes)")
}
// Or assert no leaks
try detector.assertNoLeaks() // Throws if leaks detected
```
### Peak Memory Tracking
```swift
let tracker = PeakMemoryTracker()
for i in 0..<100 {
let array = Array(repeating: 0, count: i * 100)
tracker.sample() // Record current memory
}
print("Peak memory: \(tracker.peakBytes) bytes")
print("Peak allocations: \(tracker.peakAllocations)")
```
### Allocation Profiling
```swift
let profiler = AllocationProfiler()
// Profile multiple runs
for _ in 0..<100 {
profiler.profile {
let array = Array(repeating: 0, count: 1000)
_ = array.reduce(0, +)
}
}
// Analyze results
print("Mean: \(profiler.meanBytes) bytes")
print("Median: \(profiler.medianBytes) bytes")
print("P95: \(profiler.percentileBytes(95)) bytes")
print("P99: \(profiler.percentileBytes(99)) bytes")
// Generate histogram
let histogram = profiler.histogram(buckets: 10)
for bucket in histogram.buckets {
print("\(bucket.lowerBound)-\(bucket.upperBound): \(bucket.count) (\(bucket.frequency)%)")
}
```
## Platform Differences
### macOS/iOS/watchOS/tvOS
Uses `malloc_zone_statistics` which provides:
- Current memory snapshot
- Blocks in use
- Total bytes in use
**Note**: On Darwin platforms, allocation deltas represent snapshots and can be negative due to background cleanup. This is expected behavior.
### Linux
Uses LD_PRELOAD malloc/free hooks which provide:
- Accurate allocation counting
- Deallocation tracking
- Per-thread statistics
**Note**: On Linux, you need to start tracking explicitly:
```swift
#if os(Linux)
AllocationStats.startTracking()
#endif
```
## API Overview
### `AllocationStats`
Core type representing allocation statistics.
```swift
public struct AllocationStats: Sendable, Equatable {
public let allocations: Int
public let deallocations: Int
public let bytesAllocated: Int
public var netAllocations: Int { allocations - deallocations }
public static func capture() -> AllocationStats
public static func delta(from start: AllocationStats, to end: AllocationStats) -> AllocationStats
}
```
### `AllocationTracker`
Measure allocations in code blocks.
```swift
public enum AllocationTracker {
public static func measure(_ operation: () throws -> T) rethrows -> (result: T, stats: AllocationStats)
public static func measure(_ operation: () async throws -> T) async rethrows -> (result: T, stats: AllocationStats)
public static func measure(_ operation: () throws -> Void) rethrows -> AllocationStats
public static func measure(_ operation: () async throws -> Void) async rethrows -> AllocationStats
}
```
### `LeakDetector`
Detect memory leaks by tracking net allocations.
```swift
public final class LeakDetector: Sendable {
public init()
public func hasLeaks() -> Bool
public var netAllocations: Int { get }
public var netBytes: Int { get }
public func delta() -> AllocationStats
public func assertNoLeaks(file: StaticString = #file, line: UInt = #line) throws
}
```
### `PeakMemoryTracker`
Track peak memory usage.
```swift
public final class PeakMemoryTracker: Sendable {
public init()
public func sample()
public var peakBytes: Int { get }
public var peakAllocations: Int { get }
public var samples: [AllocationStats] { get }
public var current: AllocationStats { get }
public func reset()
public static func track(_ operation: (PeakMemoryTracker) throws -> T) rethrows -> (result: T, peak: AllocationStats)
public static func track(_ operation: (PeakMemoryTracker) async throws -> T) async rethrows -> (result: T, peak: AllocationStats)
}
```
### `AllocationProfiler`
Profile allocations with statistics and histograms.
```swift
public final class AllocationProfiler: Sendable {
public init()
public func profile(_ operation: () throws -> T) rethrows -> T
public func profile(_ operation: () async throws -> T) async rethrows -> T
public var count: Int { get }
public var allMeasurements: [AllocationStats] { get }
public var meanBytes: Double { get }
public var medianBytes: Int { get }
public func percentileBytes(_ percentile: Int) -> Int
public var meanAllocations: Double { get }
public var medianAllocations: Int { get }
public func percentileAllocations(_ percentile: Int) -> Int
public func histogram(buckets: Int = 10) -> AllocationHistogram
public func reset()
}
```
## Use Cases
### 1. Performance Testing
Track memory allocations in your test suite:
```swift
func testMemoryEfficiency() throws {
let stats = AllocationTracker.measure {
myExpensiveOperation()
}
// Assert maximum allocation budget
#expect(stats.bytesAllocated <= 1024 * 1024) // Max 1MB
}
```
### 2. CI/CD Regression Detection
Profile allocations across builds:
```swift
let profiler = AllocationProfiler()
for _ in 0..<1000 {
profiler.profile {
criticalPath()
}
}
// Compare with baseline
let p95 = profiler.percentileBytes(95)
#expect(p95 <= baselineP95)
```
### 3. Production Monitoring
Detect leaks in long-running services:
```swift
let detector = LeakDetector()
while running {
handleRequest()
if detector.netAllocations > threshold {
logger.warning("Potential leak: \(detector.netBytes) bytes")
}
}
```
### 4. Memory Profiling
Understand allocation patterns:
```swift
let tracker = PeakMemoryTracker()
for batch in batches {
processBatch(batch)
tracker.sample()
}
print("Peak during processing: \(tracker.peakBytes) bytes")
```
## Requirements
- Swift 6.2+
- macOS 13+, iOS 16+, watchOS 9+, tvOS 16+, or Linux
## License
This library is released under the Apache License 2.0. See [LICENSE](LICENSE) for details.
## Related Projects
- [swift-testing-performance](https://github.com/coenttb/swift-testing-performance) - Performance measurement traits for Swift Testing