我在我的一个应用程序中遇到了一个有趣的问题.多次访问字典时,我的应用程序的内存使用量在几秒钟内就会超过一千兆字节.以下是一些显示问题的示例代码. override func viewDidLoad() { l
override func viewDidLoad() { let dictionary = ["key1":"value1"] let nsKey: NSString = "key1" let swiftKey = nsKey as String for _ in 0 ... 10000000 { dictionary[swiftKey] } }
重复访问字典会导致内存爬升,直到循环结束.我查看了仪器并看到了大量的字符串分配.事实证明使用NSString是个问题.
将nsKey更改为swift字符串就像这样修复了问题:
let nsKey = "key1"
将字典更改为NSDictionary还可以解决此问题:
let dictionary: NSDictionary = ["key1":"value1"]
有谁知道为什么使用铸造的NSString访问字典会导致如此多的堆分配,除了上面描述的那些之外还有其他任何修复吗?
这是一些照片.看起来幕后的字符串被分配并设置为自动释放(或者我是否正在读取下面的数据错误?)这可能是为什么内存使用会不断分配然后在以后耗尽?如果这是真的,这应该被视为“错误”吗? OS X和iOS上都会出现此问题.
最好的解决方案是不要在这里桥接到NSString.只需使用Swift类型.或者,正如您所发现的,您可以使用Foundation类型(NSString和NSDictionary).桥接可能需要制作临时副本.但是,在任何情况下,在这样的循环中,出于某种原因创建临时副本是非常常见的(即使您避免了这个特定问题).要解决这个问题,您需要在循环中消耗自动释放池.例如:
let dictionary = ["key1":"value1"] let nsKey: NSString = "key1" let swiftKey = nsKey as String for _ in 0 ... 10000000 { autoreleasepool { // <=== the scope of the current pool dictionary[swiftKey] } }
添加它将使您的记忆保持稳定.这在Cocoa的大循环中是很常见的事情.否则,在从顶级方法返回之前,池不会被耗尽.