Swift中指针执行deinitialize后未deallocate的内存是否可使用?
指针执行deinitialize之后还能使用对应的内存吗?
deinitialize的实际含义
deinitialize(count:)的核心作用是调用指针指向的类型的析构方法,释放该类型实例持有的所有外部资源(比如引用计数、堆内存、文件句柄等),它本身不会擦除内存的原始字节数据,也不会释放系统分配给这块内存的地址空间权限。- 对于无额外资源的平凡值类型(trivial type) 比如
Int、Float、Bool这类,它们的析构方法是空实现,deinitialize执行完之后内存里的原始字节和执行前完全一致。 - 对于非平凡类型(non-trivial type) 比如类、包含引用的结构体、
String、Array等,deinitialize执行完之后它们持有的外部资源已经被释放,内存里留存的字节已经是无效的野指针或者已释放标记。
deinitialize之后未deallocate的内存能不能访问
分两种场景:
- 访问原始字节(比如用
UnsafeRawBufferPointer读Float的字节)
只要还没调用deallocate,这块内存的读权限是正常的,不管是不是平凡类型都可以正常读取原始字节,你写的Float转字节的代码逻辑是完全可用的,因为只是读原始二进制数据,没有把它当成原类型实例访问。 - 把内存当成原类型的实例访问(比如读
UnsafeMutablePointer<MyClass>.pointee)
这种属于Swift标准定义的未定义行为:- 平凡类型(比如Int)大多数情况下不会崩溃,只是读到原来的值,但本质还是不合规的用法,不建议依赖。
- 非平凡类型大概率会直接触发崩溃,因为实例持有的资源已经被释放。
deinitialize之后触发崩溃的代码示例
用包含引用的类即可触发崩溃:
class TestClass { var value: Int init(value: Int) { self.value = value } } let ptr = UnsafeMutablePointer<TestClass>.allocate(capacity: 1) ptr.initialize(to: TestClass(value: 20)) print(ptr.pointee.value) // 正常输出 20 ptr.deinitialize(count: 1) // 下面这行访问已经被析构的类实例,会直接抛出 EXC_BAD_ACCESS 崩溃 print(ptr.pointee.value) ptr.deallocate()
注意:即使平凡类型访问不崩溃,也不要在生产代码中访问deinitialize之后未重新初始化的类型实例,这类未定义行为可能在编译器优化、Swift版本升级后出现不可预期的问题。
内容的提问来源于stack exchange,提问作者Wojciech Gonczarek
相关产品推荐
相关产品推荐

