手动内存管理
在某些场景下,需要绕过 GC 直接管理内存。Kotlin/Native 提供了 nativeHeap 用于手动内存分配和释放。
nativeHeap API
基本分配
kotlin
@OptIn(ExperimentalForeignApi::class)
import kotlinx.cinterop.*
// 分配单个对象
val intVar: IntVar = nativeHeap.alloc<IntVar>()
intVar.value = 42
// 使用完毕后必须释放
nativeHeap.free(intVar)
// 分配数组
val buffer: CPointer<ByteVar> = nativeHeap.allocArray<ByteVar>(1024)
// ... 使用 buffer ...
nativeHeap.free(buffer)RAII 包装器
kotlin
@OptIn(ExperimentalForeignApi::class)
class NativeMemory<T : CVariable>(
private val placement: NativePlacement = nativeHeap
) : AutoCloseable {
private val allocated = mutableListOf<CPointer<*>>()
inline fun <reified R : T> alloc(): R {
val ptr = placement.alloc<R>()
allocated.add(ptr.ptr)
return ptr
}
fun allocArray(size: Int): CPointer<T> {
val ptr = placement.allocArray<T>(size)
allocated.add(ptr)
return ptr
}
override fun close() {
allocated.forEach { placement.free(it) }
allocated.clear()
}
}
// 使用
NativeMemory<IntVar>().use { mem ->
val data = mem.alloc<IntVar>()
data.value = 100
} // 自动释放Arena 分配器
自定义 Arena
kotlin
@OptIn(ExperimentalForeignApi::class)
class Arena : NativePlacement {
private val allocations = mutableListOf<CPointer<*>>()
override fun alloc(size: Long, align: Int): NativePointed {
val ptr = nativeHeap.alloc(size, align)
allocations.add(ptr.rawPtr)
return ptr
}
override fun alloc(size: Int, align: Int): NativePointed {
return alloc(size.toLong(), align)
}
fun clear() {
allocations.forEach { nativeHeap.free(it) }
allocations.clear()
}
}
// 使用
val arena = Arena()
val ptr1 = arena.alloc<IntVar>()
val ptr2 = arena.allocArray<ByteVar>(100)
// ... 使用 ...
arena.clear() // 一次性释放所有内存池
固定大小对象池
kotlin
@OptIn(ExperimentalForeignApi::class)
class FixedSizePool<T : CVariable>(
private val blockSize: Int,
initialCapacity: Int = 16
) {
private val freeList = ArrayDeque<CPointer<T>>()
init {
repeat(initialCapacity) {
freeList.add(nativeHeap.allocArray(blockSize))
}
}
fun acquire(): CPointer<T> {
return synchronized(freeList) {
if (freeList.isNotEmpty()) {
freeList.removeFirst()
} else {
nativeHeap.allocArray(blockSize)
}
}
}
fun release(ptr: CPointer<T>) {
synchronized(freeList) {
// 清零内存
platform.posix.memset(ptr, 0, blockSize.toULong())
freeList.add(ptr)
}
}
fun destroy() {
freeList.forEach { nativeHeap.free(it) }
freeList.clear()
}
}
// 使用
val bufferPool = FixedSizePool<ByteVar>(4096, initialCapacity = 10)
val buffer = bufferPool.acquire()
// ... 使用 buffer ...
bufferPool.release(buffer)性能优化
批量分配
kotlin
@OptIn(ExperimentalForeignApi::class)
class BatchAllocator(private val batchSize: Int = 1024) {
private var currentBatch: CPointer<ByteVar>? = null
private var offset = 0
fun allocBytes(size: Int): CPointer<ByteVar> {
if (currentBatch == null || offset + size > batchSize) {
currentBatch = nativeHeap.allocArray(batchSize)
offset = 0
}
val result = currentBatch!! + offset
offset += size
return result
}
// 注意:批量分配无法单独释放,只能整批释放
fun reset() {
currentBatch?.let { nativeHeap.free(it) }
currentBatch = null
offset = 0
}
}对齐分配
kotlin
@OptIn(ExperimentalForeignApi::class)
fun allocAligned(size: Int, alignment: Int): CPointer<ByteVar> {
val rawPtr = nativeHeap.allocArray<ByteVar>(size + alignment)
val addr = rawPtr.rawValue.toLong()
val alignedAddr = (addr + alignment - 1) and (alignment - 1).inv().toLong()
return alignedAddr.toCPointer()!!
}
// 使用 SIMD 需要16字节对齐
val simdBuffer = allocAligned(1024, 16)内存泄漏检测
追踪分配
kotlin
@OptIn(ExperimentalForeignApi::class)
object MemoryTracker {
private val allocations = mutableMapOf<Long, AllocationInfo>()
data class AllocationInfo(
val size: Int,
val stackTrace: String
)
fun track(ptr: CPointer<*>, size: Int) {
synchronized(allocations) {
allocations[ptr.rawValue.toLong()] = AllocationInfo(
size = size,
stackTrace = Exception().stackTraceToString()
)
}
}
fun untrack(ptr: CPointer<*>) {
synchronized(allocations) {
allocations.remove(ptr.rawValue.toLong())
}
}
fun reportLeaks() {
synchronized(allocations) {
if (allocations.isNotEmpty()) {
println("=== Memory Leaks Detected ===")
allocations.forEach { (addr, info) ->
println("Address: 0x${addr.toString(16)}")
println("Size: ${info.size} bytes")
println("Allocated at:\n${info.stackTrace}")
println("---")
}
}
}
}
}
// 包装 nativeHeap
@OptIn(ExperimentalForeignApi::class)
object TrackedHeap {
inline fun <reified T : CVariable> alloc(): T {
val ptr = nativeHeap.alloc<T>()
MemoryTracker.track(ptr.ptr, sizeOf<T>().toInt())
return ptr
}
fun <T : CVariable> free(ptr: T) {
MemoryTracker.untrack(ptr.ptr)
nativeHeap.free(ptr)
}
}与 C 内存互操作
接收 C 分配的内存
kotlin
@OptIn(ExperimentalForeignApi::class)
import platform.posix.malloc
import platform.posix.free
// C: void* get_buffer(size_t size)
fun receiveCMemory(size: Int): CPointer<ByteVar>? {
val cPtr = malloc(size.toULong())?.reinterpret<ByteVar>()
// 使用完毕后用 C 的 free 释放
// free(cPtr)
return cPtr
}传递给 C 代码
kotlin
@OptIn(ExperimentalForeignApi::class)
fun passToCCode() {
// Kotlin 分配
val buffer = nativeHeap.allocArray<ByteVar>(1024)
// 传递给 C 函数
// C: void process_buffer(uint8_t* data, size_t size)
process_buffer(buffer, 1024u)
// Kotlin 负责释放
nativeHeap.free(buffer)
}手动内存管理提供了最大的控制权,但需要严格的纪律避免泄漏。合理使用 RAII 模式和内存池能够在保证安全的同时获得最佳性能。