Swift中多次调用Decimal的formatted()方法为何性能逐渐下降?
问题:Decimal.formatted() 重复调用性能持续下降的原因
我需要给整数做三位分隔,所以用了Decimal类型的formatted()方法。但每次对随机整数调用这个方法100,000次时,性能会越来越差,想知道这是为什么。
测试代码
import Foundation /// 计时函数 func calculateTime(block : (() -> Void)) { let start = DispatchTime.now() block() let end = DispatchTime.now() let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds let timeInterval = Double(nanoTime) / 1_000_000_000 print("Time: \(timeInterval) seconds") } calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } } calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } } calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } } calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } } calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } } calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } } calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } } calculateTime { for _ in 0...100_000 { _ = Decimal(Int.random(in: 0...Int.max)).formatted() } }
执行结果
Time: 0.9492465 seconds Time: 3.29213125 seconds Time: 7.988363667 seconds Time: 15.165178292 seconds Time: 17.305036583 seconds Time: 25.0114935 seconds Time: 35.746310417 seconds Time: 47.024551125 seconds
核心原因分析
这种性能持续下降的现象,本质是**formatted()方法依赖的系统本地化缓存机制出现了内存累积或资源泄漏**,具体拆解:
- 本地化对象缓存膨胀:
formatted()默认使用当前系统的本地化配置,每次调用都会隐式创建或复用NumberFormatter相关的本地化上下文。高频循环中,这些对象的缓存未被正确回收,内存中累积大量未释放的格式化条目,后续调用需要在臃肿的缓存中查找或创建对象,耗时递增。 - 随机数范围的放大效应:每次生成的随机整数覆盖0到
Int.max的全范围,Decimal格式化逻辑需要处理不同位数的数字,触发更多不同的格式化规则缓存条目,进一步加速缓存膨胀,提升后续调用的查找和计算成本。 - ARC延迟回收的叠加:Swift的ARC虽能管理内存,但系统框架内部的本地化对象可能持有外部无法控制的强引用,这些对象不会在循环结束后立即释放,多次循环叠加后内存占用持续上升,间接拖慢整体执行速度。
优化方案
要解决性能问题,直接复用NumberFormatter对象即可避免重复创建和缓存膨胀,同时满足三位分隔的需求:
import Foundation func calculateTime(block : (() -> Void)) { let start = DispatchTime.now() block() let end = DispatchTime.now() let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds let timeInterval = Double(nanoTime) / 1_000_000_000 print("Time: \(timeInterval) seconds") } // 预先创建并配置NumberFormatter,复用同一个实例 let formatter = NumberFormatter() formatter.numberStyle = .decimal calculateTime { for _ in 0...100_000 { _ = formatter.string(from: NSNumber(value: Int.random(in: 0...Int.max))) } } calculateTime { for _ in 0...100_000 { _ = formatter.string(from: NSNumber(value: Int.random(in: 0...Int.max))) } }
复用NumberFormatter后,每次调用仅使用同一个格式化上下文,不会产生缓存膨胀问题,多次执行的耗时会保持稳定。
内容的提问来源于stack exchange,提问作者Mac
相关产品推荐
相关产品推荐

