Swiftバージョン
terminal.txt
$ swift --version
Apple Swift version 4.0.2 (swiftlang-900.0.69.2 clang-900.0.38)
Target: x86_64-apple-macosx10.9
結論
UnsafeMutableRawPointerの deallocate(bytes:, alignedTo:) メソッドを呼んでも
initializeMemory(as:, to:) メソッドでバインドしたインスタンスは解放されない。
回避策として、一旦 UnsafeMutablePointer<T> に変換してから、こちらのメソッドを通して解放する
解放されないコード
解放されないコード.swift
voidPointer.deallocate(bytes: MemoryLayout<Foo>.stride, alignedTo: MemoryLayout<Foo>.alignment)
解放されるコード
解放されるコード.swift
// UnsafeMutabeRawPointerをUnsafeMutablePointerに変換しています
let opaque = OpaquePointer(self.voidPointer)
let fooPointer = UnsafeMutablePointer<Foo>(opaque)
// UnsafeMutablePointerを通して解放すると問題なく解放される
fooPointer.deinitialize(count: 1) //ただしこれがないとだめ
fooPointer.deallocate(capacity: MemoryLayout<Foo>.size)
詳細
解放されないコード.swift
解放されないコード.swift
class Foo {
// 呼ばれない
deinit {
print(type(of: self), #function)
}
}
class Main {
var voidPointer: UnsafeMutableRawPointer
init(voidPointer: UnsafeMutableRawPointer) {
self.voidPointer = voidPointer
}
deinit {
print(type(of: self), #function)
// ここでFooインスタンスを解放しているが、解放されない
voidPointer.deallocate(bytes: MemoryLayout<Foo>.stride, alignedTo: MemoryLayout<Foo>.alignment)
}
}
do {
let f = Foo()
let fp = UnsafeMutableRawPointer.allocate(bytes: MemoryLayout<Foo>.size, alignedTo: 1)
fp.initializeMemory(as: Foo.self, to: f)
let _ = Main(voidPointer: fp)
}
解放されるコード
解放されるコード.swift
class Foo {
// 呼ばれる
deinit {
print(type(of: self), #function)
}
}
class Main {
var voidPointer: UnsafeMutableRawPointer
init(voidPointer: UnsafeMutableRawPointer) {
self.voidPointer = voidPointer
}
deinit {
print(type(of: self), #function)
// UnsafeMutablePointerへ一旦変換してから解放する
let opaque = OpaquePointer(self.voidPointer)
let fooPointer = UnsafeMutablePointer<Foo>(opaque)
fooPointer.deinitialize(count: 1)
fooPointer.deallocate(capacity: MemoryLayout<Foo>.size)
}
}
do {
let f = Foo()
let fp = UnsafeMutableRawPointer.allocate(bytes: MemoryLayout<Foo>.size, alignedTo: 1)
fp.initializeMemory(as: Foo.self, to: f)
let _ = Main(voidPointer: fp)
}