有谁能帮忙解释一下为什么下面的代码在运行时要消耗超过100MB的RAM?
public struct Trie<Element : Hashable> {
private var children: [Element:Trie<Element>]
private var endHere : Bool
public init() {
children = [:]
endHere = false
}
public init<S : SequenceType where S.Generator.Element == Element>(_ seq: S) {
self.init(gen: seq.generate())
}
private init<G : GeneratorType where G.Element == Element>(var gen: G) {
if let head = gen.next() {
(children, endHere) = ([head:Trie(gen:gen)], false)
} else {
(children, endHere) = ([:], true)
}
}
private mutating func insert<G : GeneratorType where G.Element == Element>(var gen: G) {
if let head = gen.next() {
let _ = children[head]?.insert(gen) ?? { children[head] = Trie(gen: gen) }()
} else {
endHere = true
}
}
public mutating func insert<S : SequenceType where S.Generator.Element == Element>(seq: S) {
insert(seq.generate())
}
}
var trie = Trie<UInt32>()
for i in 0..<300000 {
trie.insert([UInt32(i), UInt32(i+1), UInt32(i+2)])
}
根据我的计算,上述数据结构的总内存消耗应该在以下位置附近…
3 * count * sizeof(Trie<UInt32>)
或-
3 * 300,000 * 9 = 8,100,000 bytes = ~8 MB
在运行时,这个数据结构如何消耗超过100MB的数据?
最佳答案
sizeof
只报告堆栈上的静态内存占用,Dictionary
只是对其内部引用类型实现的引用的一种包装,也是对写时拷贝的支持。换句话说,字典的键值对和哈希表是在堆上分配的,而sizeof
不包括在堆中。这适用于所有其他SWIFT托收类型。
在您的例子中,您创建了三个Trie
-并且间接地创建了三个字典-每次迭代300000次。如果@macmade提到的96字节分配是字典(例如其散列桶)的最小开销,我不会感到惊讶。
此外,还可能存在与不断增长的存储有关的成本。因此,您可以尝试查看在字典上设置minimumCapacity
是否有帮助。另一方面,如果不需要每次迭代生成发散路径,可以考虑使用间接枚举作为替代,例如。
public enum Trie<Element> {
indirect case Next(Element, Trie<Element>)
case End
}
这会占用更少的内存。
关于xcode - Swift词典的内存消耗是天文数字,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34080471/