0
# Memory Management
1
2
The memory management system in Scala Native nativelib provides zone-based allocation with automatic cleanup, type-safe pointers, and low-level memory operations for efficient native code integration.
3
4
## Core Types
5
6
### Zone
7
8
Zone provides scoped memory allocation with automatic cleanup, preventing memory leaks in native code.
9
10
```scala { .api }
11
trait Zone {
12
def alloc(size: CSize): Ptr[Byte]
13
def alloc(size: Int): Ptr[Byte]
14
def alloc(size: UInt): Ptr[Byte]
15
def alloc(size: ULong): Ptr[Byte]
16
def close(): Unit
17
def isOpen: Boolean
18
def isClosed: Boolean
19
}
20
```
21
22
**Zone.alloc methods**:
23
- `alloc(size: CSize)` - Allocate memory of given size in bytes
24
- `alloc(size: Int)` - Allocate memory, converting Int to CSize
25
- `alloc(size: UInt)` - Allocate memory, converting UInt to CSize
26
- `alloc(size: ULong)` - Allocate memory, converting ULong to CSize
27
28
### Zone Companion Object
29
30
```scala { .api }
31
object Zone {
32
def acquire[T](f: Zone => T): T
33
def open(): Zone
34
}
35
```
36
37
**Methods**:
38
- `acquire[T](f: Zone => T): T` - Execute function with fresh zone, automatically cleanup
39
- `open(): Zone` - Create new zone allocator (must call `close()` manually)
40
41
### Ptr[T]
42
43
Type-safe pointer wrapper providing memory access with compile-time type checking.
44
45
```scala { .api }
46
final class Ptr[T] {
47
// Memory access
48
def unary_!(implicit tag: Tag[T]): T
49
def unary_!_=(value: T)(implicit tag: Tag[T]): Unit
50
51
// Pointer arithmetic
52
def +(offset: Int)(implicit tag: Tag[T]): Ptr[T]
53
def +(offset: Long)(implicit tag: Tag[T]): Ptr[T]
54
def +(offset: Size)(implicit tag: Tag[T]): Ptr[T]
55
def +(offset: USize)(implicit tag: Tag[T]): Ptr[T]
56
57
def -(offset: Int)(implicit tag: Tag[T]): Ptr[T]
58
def -(offset: Long)(implicit tag: Tag[T]): Ptr[T]
59
def -(offset: Size)(implicit tag: Tag[T]): Ptr[T]
60
def -(offset: USize)(implicit tag: Tag[T]): Ptr[T]
61
def -(other: Ptr[T])(implicit tag: Tag[T]): CPtrDiff
62
63
// Array-style access
64
def apply(offset: Int)(implicit tag: Tag[T]): T
65
def apply(offset: Long)(implicit tag: Tag[T]): T
66
def apply(offset: Size)(implicit tag: Tag[T]): T
67
def apply(offset: USize)(implicit tag: Tag[T]): T
68
69
def update(offset: Int, value: T)(implicit tag: Tag[T]): Unit
70
def update(offset: Long, value: T)(implicit tag: Tag[T]): Unit
71
def update(offset: Size, value: T)(implicit tag: Tag[T]): Unit
72
def update(offset: USize, value: T)(implicit tag: Tag[T]): Unit
73
74
// Conversions
75
def toInt: Int
76
def toLong: Long
77
}
78
```
79
80
**Memory access**:
81
- `unary_!` - Dereference pointer to read value
82
- `unary_!_=` - Dereference pointer to write value
83
84
**Pointer arithmetic**:
85
- `+` / `-` with numeric offsets - Move pointer by offset * sizeof(T)
86
- `-(other: Ptr[T])` - Calculate pointer difference
87
88
**Array access**:
89
- `apply(offset)` - Read value at pointer + offset
90
- `update(offset, value)` - Write value at pointer + offset
91
92
### Size Types
93
94
Platform-dependent size types that match C `size_t` and `ssize_t` behavior.
95
96
```scala { .api }
97
// Int on 32-bit architectures, Long on 64-bit architectures
98
type Size = /* platform dependent */
99
type CPtrDiff = Size
100
type CSSize = Size
101
```
102
103
## Memory Allocation Functions
104
105
### Generic Allocation
106
107
```scala { .api }
108
def alloc[T](implicit tag: Tag[T]): Ptr[T]
109
def alloc[T](count: Int)(implicit tag: Tag[T]): Ptr[T]
110
def alloc[T](count: UInt)(implicit tag: Tag[T]): Ptr[T]
111
def alloc[T](count: ULong)(implicit tag: Tag[T]): Ptr[T]
112
def alloc[T](count: CSize)(implicit tag: Tag[T]): Ptr[T]
113
```
114
115
**Allocation functions**:
116
- `alloc[T]()` - Allocate single instance of type T
117
- `alloc[T](count)` - Allocate array of count instances of type T
118
119
### Stack Allocation
120
121
```scala { .api }
122
def stackalloc[T](implicit tag: Tag[T]): Ptr[T]
123
def stackalloc[T](count: Int)(implicit tag: Tag[T]): Ptr[T]
124
def stackalloc[T](count: UInt)(implicit tag: Tag[T]): Ptr[T]
125
def stackalloc[T](count: ULong)(implicit tag: Tag[T]): Ptr[T]
126
def stackalloc[T](count: CSize)(implicit tag: Tag[T]): Ptr[T]
127
```
128
129
**Stack allocation functions**:
130
- `stackalloc[T]()` - Allocate single instance on stack
131
- `stackalloc[T](count)` - Allocate array on stack (automatically freed on scope exit)
132
133
## Memory Operations
134
135
### Low-level Memory Functions
136
137
```scala { .api }
138
def memcpy(dest: Ptr[Byte], src: Ptr[Byte], count: CSize): Unit
139
def memmove(dest: Ptr[Byte], src: Ptr[Byte], count: CSize): Unit
140
def memset(ptr: Ptr[Byte], value: Int, count: CSize): Unit
141
def memcmp(ptr1: Ptr[Byte], ptr2: Ptr[Byte], count: CSize): Int
142
```
143
144
**Memory manipulation**:
145
- `memcpy` - Copy memory blocks (undefined behavior for overlapping regions)
146
- `memmove` - Copy memory blocks (safe for overlapping regions)
147
- `memset` - Fill memory with byte value
148
- `memcmp` - Compare memory blocks, returns 0 if equal
149
150
### Type Information
151
152
```scala { .api }
153
def sizeOf[T](implicit tag: Tag[T]): CSize
154
def alignmentOf[T](implicit tag: Tag[T]): CSize
155
def sizeof[T](implicit tag: Tag[T]): CSize
156
```
157
158
**Type queries**:
159
- `sizeOf[T]` - Get size in bytes of type T
160
- `alignmentOf[T]` - Get alignment requirement of type T
161
- `sizeof[T]` - Alias for sizeOf
162
163
## Usage Examples
164
165
### Basic Zone Usage
166
167
```scala
168
import scala.scalanative.unsafe._
169
170
// Automatic cleanup with Zone.acquire
171
Zone.acquire { implicit z =>
172
val ptr = alloc[CInt](10) // allocate array of 10 integers
173
ptr(0) = 42
174
ptr(1) = 84
175
176
val value = ptr(0) // read first element
177
// memory automatically freed when leaving scope
178
}
179
```
180
181
### Manual Zone Management
182
183
```scala
184
import scala.scalanative.unsafe._
185
186
val zone = Zone.open()
187
try {
188
implicit val z: Zone = zone
189
val ptr = alloc[CDouble](5)
190
ptr(0) = 3.14159
191
// ... use pointer
192
} finally {
193
zone.close() // manual cleanup
194
}
195
```
196
197
### Pointer Arithmetic
198
199
```scala
200
import scala.scalanative.unsafe._
201
202
Zone.acquire { implicit z =>
203
val array = alloc[CInt](10)
204
205
// Initialize array
206
var i = 0
207
while (i < 10) {
208
array(i) = i * i
209
i += 1
210
}
211
212
// Pointer arithmetic
213
val second = array + 1 // points to array[1]
214
val value = !second // dereference: reads array[1]
215
216
// Calculate pointer difference
217
val end = array + 10
218
val size = end - array // returns 10
219
}
220
```
221
222
### Stack Allocation
223
224
```scala
225
import scala.scalanative.unsafe._
226
227
def processBuffer(): CInt = {
228
val buffer = stackalloc[CChar](256) // 256 bytes on stack
229
230
// Use buffer for temporary operations
231
!buffer = 'H'.toByte
232
!(buffer + 1) = 'i'.toByte
233
!(buffer + 2) = 0.toByte // null terminator
234
235
// buffer automatically freed on return
236
42
237
}
238
```
239
240
## Type-Safe Memory Operations
241
242
### Tag System
243
244
The Tag system provides type-safe access to memory with automatic size and alignment information:
245
246
```scala { .api }
247
sealed abstract class Tag[T] {
248
def size: Int
249
def alignment: Int
250
def load(ptr: Ptr[T]): T
251
def store(ptr: Ptr[T], value: T): Unit
252
}
253
254
object Tag {
255
// Platform pointer size
256
def SizeOfPtr: Int
257
258
// Tag implementations for pointer types
259
final case class Ptr[T](of: Tag[T]) extends Tag[unsafe.Ptr[T]]
260
261
// Built-in tags for primitive types
262
case object Size extends Tag[unsafe.Size]
263
case object Boolean extends Tag[Boolean]
264
case object Byte extends Tag[Byte]
265
case object UByte extends Tag[UByte]
266
case object Short extends Tag[Short]
267
case object UShort extends Tag[UShort]
268
case object Int extends Tag[Int]
269
case object UInt extends Tag[UInt]
270
case object Long extends Tag[Long]
271
case object ULong extends Tag[ULong]
272
case object Float extends Tag[Float]
273
case object Double extends Tag[Double]
274
case object Char extends Tag[Char]
275
276
// Tags for structured types
277
case class CArray[T, N <: Nat](of: Tag[T], n: Tag[N]) extends Tag[CArray[T, N]]
278
case class CStruct1[T1](tag1: Tag[T1]) extends Tag[CStruct1[T1]]
279
case class CStruct2[T1, T2](tag1: Tag[T1], tag2: Tag[T2]) extends Tag[CStruct2[T1, T2]]
280
// ... continues for CStruct3 through CStruct22
281
}
282
```
283
284
**Tag system methods**:
285
- `size` - Size in bytes of the type
286
- `alignment` - Memory alignment requirement
287
- `load(ptr)` - Type-safe memory read
288
- `store(ptr, value)` - Type-safe memory write
289
290
### Runtime Memory Intrinsics
291
292
Low-level memory operations for performance-critical code:
293
294
```scala { .api }
295
object Intrinsics {
296
// Stack allocation (automatic cleanup)
297
def stackalloc[T](): RawPtr
298
def stackalloc[T](size: RawSize): RawPtr
299
300
// Raw memory load operations
301
def loadBoolean(rawptr: RawPtr): Boolean
302
def loadChar(rawptr: RawPtr): Char
303
def loadByte(rawptr: RawPtr): Byte
304
def loadShort(rawptr: RawPtr): Short
305
def loadInt(rawptr: RawPtr): Int
306
def loadLong(rawptr: RawPtr): Long
307
def loadFloat(rawptr: RawPtr): Float
308
def loadDouble(rawptr: RawPtr): Double
309
def loadRawPtr(rawptr: RawPtr): RawPtr
310
def loadRawSize(rawptr: RawPtr): RawSize
311
def loadObject(rawptr: RawPtr): Object
312
313
// Raw memory store operations
314
def storeBoolean(rawptr: RawPtr, value: Boolean): Unit
315
def storeChar(rawptr: RawPtr, value: Char): Unit
316
def storeByte(rawptr: RawPtr, value: Byte): Unit
317
def storeShort(rawptr: RawPtr, value: Short): Unit
318
def storeInt(rawptr: RawPtr, value: Int): Unit
319
def storeLong(rawptr: RawPtr, value: Long): Unit
320
def storeFloat(rawptr: RawPtr, value: Float): Unit
321
def storeDouble(rawptr: RawPtr, value: Double): Unit
322
def storeRawPtr(rawptr: RawPtr, value: RawPtr): Unit
323
def storeRawSize(rawptr: RawPtr, value: RawSize): Unit
324
def storeObject(rawptr: RawPtr, value: Object): Unit
325
326
// Pointer arithmetic
327
def elemRawPtr(rawptr: RawPtr, offset: RawSize): RawPtr
328
def elemRawPtr(rawptr: RawPtr, offset: Int): RawPtr
329
330
// Type casting intrinsics
331
def castRawPtrToObject(rawptr: RawPtr): Object
332
def castObjectToRawPtr(obj: Object): RawPtr
333
def castIntToFloat(int: Int): Float
334
def castFloatToInt(float: Float): Int
335
def castLongToDouble(long: Long): Double
336
def castDoubleToLong(double: Double): Long
337
def castRawPtrToLong(rawptr: RawPtr): Long
338
def castRawPtrToInt(rawptr: RawPtr): Int
339
def castIntToRawPtr(int: Int): RawPtr
340
def castLongToRawPtr(long: Long): RawPtr
341
def castIntToRawSize(int: Int): RawSize
342
def castIntToRawSizeUnsigned(int: Int): RawSize
343
def castLongToRawSize(long: Long): RawSize
344
def castRawSizeToInt(size: RawSize): Int
345
def castRawSizeToLong(size: RawSize): Long
346
347
// Unsigned arithmetic
348
def divUInt(l: Int, r: Int): Int
349
def remUInt(l: Int, r: Int): Int
350
def divULong(l: Long, r: Long): Long
351
def remULong(l: Long, r: Long): Long
352
353
// Unsigned type conversions
354
def byteToUInt(b: Byte): Int
355
def byteToULong(b: Byte): Long
356
def shortToUInt(v: Short): Int
357
def shortToULong(v: Short): Long
358
def intToULong(v: Int): Long
359
def uintToFloat(v: Int): Float
360
def ulongToFloat(v: Long): Float
361
def uintToDouble(v: Int): Double
362
def ulongToDouble(v: Long): Double
363
}
364
```
365
366
### Advanced Memory Usage
367
368
#### Using the Tag System
369
370
```scala
371
import scala.scalanative.unsafe._
372
import scala.scalanative.runtime._
373
374
Zone.acquire { implicit z =>
375
// Type-safe generic allocation
376
def allocTyped[T](implicit tag: Tag[T]): Ptr[T] = {
377
val ptr = alloc[Byte](tag.size)
378
ptr.asInstanceOf[Ptr[T]]
379
}
380
381
// Get size information at runtime
382
val intSize = Tag.Int.size // Size of Int (4 bytes)
383
val alignment = Tag.Long.alignment // Alignment of Long (8 bytes)
384
385
// Type-safe memory operations
386
val ptr = allocTyped[Int]
387
Tag.Int.store(ptr, 42)
388
val value = Tag.Int.load(ptr) // value = 42
389
}
390
```
391
392
#### Raw Memory Operations
393
394
```scala
395
import scala.scalanative.runtime.Intrinsics._
396
import scala.scalanative.unsafe._
397
398
// Stack allocation with automatic cleanup
399
def processBuffer(): Int = {
400
val buffer = stackalloc[Byte](1024.toULong)
401
402
// Direct memory operations (no bounds checking)
403
storeInt(buffer, 0x12345678)
404
storeByte(elemRawPtr(buffer, 4), 0xFF.toByte)
405
406
// Read back
407
val intValue = loadInt(buffer) // 0x12345678
408
val byteValue = loadByte(elemRawPtr(buffer, 4)) // 0xFF
409
410
intValue
411
// buffer automatically freed on function exit
412
}
413
```
414
415
#### Performance-Critical Memory Access
416
417
```scala
418
import scala.scalanative.runtime.Intrinsics._
419
import scala.scalanative.unsafe._
420
421
Zone.acquire { implicit z =>
422
val array = alloc[Double](1000)
423
val basePtr = toRawPtr(array)
424
425
// Initialize using raw operations for maximum performance
426
var i = 0
427
while (i < 1000) {
428
val offset = castIntToRawSize(i * 8) // sizeof(Double) = 8
429
val elemPtr = elemRawPtr(basePtr, offset)
430
storeDouble(elemPtr, i.toDouble * 1.5)
431
i += 1
432
}
433
434
// Process data using vectorized operations (hypothetical)
435
// Raw access allows for SIMD optimization
436
}
437
```
438
439
## Best Practices
440
441
1. **Always use Zone.acquire** when possible for automatic memory management
442
2. **Check for null pointers** when interfacing with C libraries
443
3. **Be careful with pointer arithmetic** - ensure bounds checking when needed
444
4. **Use type tags consistently** for generic operations
445
5. **Prefer stack allocation** for small, temporary buffers
446
6. **Don't mix different allocation methods** (zone vs malloc) for the same memory
447
7. **Use raw intrinsics sparingly** - only for performance-critical sections
448
8. **Validate pointer arithmetic** - raw operations bypass safety checks
449
9. **Consider alignment** - use Tag system for proper alignment information
450
10. **Profile memory-intensive code** - intrinsics can provide significant speedups