swift 字符串追加机制

swift string append mechanics

当我在Swift中使用+=运算符将一个字符串追加到另一个字符串时,代码中执行了什么过程?如果我执行 str1+=str2,是在 str1 的末尾分配内存并将 str2 复制到那里,还是为新字符串的组合长度分配内存,然后复制字符串? 我编写了一种将字符串附加在一起的线性方法和一种平分方法,并对这两种方法进行了计时。平分方法仅比线性方法快 2 倍。附加过程中是否有任何机制可以解释这两种方法如此相似的时间?

    var start = NSDate().timeIntervalSince1970
    let _ = stringMe(400000000, str:"Developers! ")
    var end = NSDate().timeIntervalSince1970

    var duration = end - start;
    print("stringMe takes: \(duration)");


    start = NSDate().timeIntervalSince1970
     let _ = stringMe2(400000000, str:"Developers! ")
     end = NSDate().timeIntervalSince1970

    duration = end - start;
    print("stringMe2 takes: \(duration)");


func stringMe(n:Int, str:String)-> String {

    var string = ""

    for _ in 0..<n{
        string += str
    }


    return string
}

func stringMe2(n:Int, str:String)->String
{

    var string = str

    var currentWritten = 1

    while currentWritten < n {

        if currentWritten*2>n {

            string += stringMe2(n-currentWritten, str: str)

            break

        }


        currentWritten*=2
        string+=string

    }

    return string

}

我不知道您的计算机有多少内存,但我们正在查看最后一组串联中的 4.8G 字符串。这意味着当您按顺序增长字符串时,堆管理将不太可能导致页面错误。

假设每个字符串连接都会分配一个新的内存块,然后复制两个字符串以获得结果,然后释放原始字符串的内存以供以后重复使用。

顺序地,从第3次级联开始,前两次操作释放的内存足够大,可以容纳下一个结果。这不会导致页面错误,直到它非常接近限制(如果它甚至如此)。

另一方面,指数复制永远不会找到足够大的可重用内存来满足下一个结果,并且会达到虚拟内存垃圾阈值,此时它需要将源和页面的部分页面调出 in-out一些目的地。

顺序串联所需的内存永远不会超过源和目标的大小加上字符串的一个实例:即 2n + 1 倍的字符串(大约:9.6Gb)。在接下来的两个操作中,它将释放 n 和 n+1,这将给它足够的空间来容纳至少一个 n+3 的副本。

指数级联需要一个源副本和一个两倍大的目标副本。 n + 2*n 在内存中用于复制操作(大约 14.4Gb)。在接下来的操作中,它将释放 3*n 但结果所需的内存块将是 4*n,然后释放 7*n 它将需要 8*n 等等,永远找不到足够大的块

随着指数复制的进行,它会创建越来越多的分页,而顺序方法甚至可能达不到阈值。

总而言之,您的数字太大,无法进行有意义的比较,因为您 运行 遇到了干扰结果的内存问题。