Swift 如何解决内存问题 "Leak"
Swift How to solve a Memory "Leak"
我遇到了我不明白的内存“泄漏”。我有一个缓存 class,其目的是限制大量数据项的实例数。即使它存储了这些项目的 NO 个实例,它们也会以某种方式保留下来。如果它们来自后台线程,我相信它们会在任务完成后被释放。但是,当然,如代码所示,它们在主线程上仍然存在。
这发生在 iPadOS 14.8、iPadOS 15 和 MacCatalyst 上。
我错过了什么或不明白什么?
class DataCache {
var id: String
var data: Data? {
get {
let url = FileManager.default.temporaryDirectory
.appendingPathComponent("\(id).txt")
return try! Data(contentsOf: url)
}
set {
let url = FileManager.default.temporaryDirectory
.appendingPathComponent("\(id).txt")
try! newValue!.write(to: url)
}
}
init(id: String, data: Data) {
self.id = id
self.data = data
}
}
class Item {
static var selection = [Item]()
static var items = [String:Item]()
var id: String = UUID().uuidString
var itemData: DataCache
init() {
itemData = DataCache(id: id,
data: Data(String(repeating: "dummy", count: 4_000_000).utf8)
)
}
required init(_ other: Item) {
self.itemData = DataCache(id: self.id, data: other.itemData.data!)
}
func duplicate(times: Int) {
for index in 0..<times {
print(index)
Item.selection.append(Item(self))
}
}
}
@main struct Main {
static func main() throws {
let item = Item()
perform(item)
performOnSelection() { item in
let _ = Item(item)
}
while (true) {}
}
static func perform(_ item: Item) {
item.duplicate(times: 100)
}
static func performOnSelection(perform action: @escaping (Item)->Void) {
var done = false
DispatchQueue.global().async {
for item in Item.selection {
action(item)
}
done = true
}
while !done { sleep (1) }
}
}
您有正在创建的自动释放对象。插入一个 autoreleasepool
以定期排空池,例如:
func performOnSelection(perform action: @escaping (Item) -> Void) {
...
autoreleasepool {
perform(item)
}
performOnSelection() { item in
autoreleasepool {
let _ = Item(item)
}
}
...
}
和
func duplicate(times: Int) {
for index in 0..<times {
print(index)
autoreleasepool { [self] in
Item.selection.append(Item(self))
}
}
}
例如没有 autoreleasepool
:
还有:
当它不处理所有那些挥之不去的自动释放对象时,它会变得更快。峰值内存使用量从 3.4gb 变为 47mb。
我遇到了我不明白的内存“泄漏”。我有一个缓存 class,其目的是限制大量数据项的实例数。即使它存储了这些项目的 NO 个实例,它们也会以某种方式保留下来。如果它们来自后台线程,我相信它们会在任务完成后被释放。但是,当然,如代码所示,它们在主线程上仍然存在。
这发生在 iPadOS 14.8、iPadOS 15 和 MacCatalyst 上。
我错过了什么或不明白什么?
class DataCache {
var id: String
var data: Data? {
get {
let url = FileManager.default.temporaryDirectory
.appendingPathComponent("\(id).txt")
return try! Data(contentsOf: url)
}
set {
let url = FileManager.default.temporaryDirectory
.appendingPathComponent("\(id).txt")
try! newValue!.write(to: url)
}
}
init(id: String, data: Data) {
self.id = id
self.data = data
}
}
class Item {
static var selection = [Item]()
static var items = [String:Item]()
var id: String = UUID().uuidString
var itemData: DataCache
init() {
itemData = DataCache(id: id,
data: Data(String(repeating: "dummy", count: 4_000_000).utf8)
)
}
required init(_ other: Item) {
self.itemData = DataCache(id: self.id, data: other.itemData.data!)
}
func duplicate(times: Int) {
for index in 0..<times {
print(index)
Item.selection.append(Item(self))
}
}
}
@main struct Main {
static func main() throws {
let item = Item()
perform(item)
performOnSelection() { item in
let _ = Item(item)
}
while (true) {}
}
static func perform(_ item: Item) {
item.duplicate(times: 100)
}
static func performOnSelection(perform action: @escaping (Item)->Void) {
var done = false
DispatchQueue.global().async {
for item in Item.selection {
action(item)
}
done = true
}
while !done { sleep (1) }
}
}
您有正在创建的自动释放对象。插入一个 autoreleasepool
以定期排空池,例如:
func performOnSelection(perform action: @escaping (Item) -> Void) {
...
autoreleasepool {
perform(item)
}
performOnSelection() { item in
autoreleasepool {
let _ = Item(item)
}
}
...
}
和
func duplicate(times: Int) {
for index in 0..<times {
print(index)
autoreleasepool { [self] in
Item.selection.append(Item(self))
}
}
}
例如没有 autoreleasepool
:
还有:
当它不处理所有那些挥之不去的自动释放对象时,它会变得更快。峰值内存使用量从 3.4gb 变为 47mb。