我有一个
for-loop
,它会执行一些操作并在执行期间分配大约 200MB 的空间。
即使在 for 循环执行几分钟后,数据也不会被释放。
它只会更改数据,不会创建随后需要存储的新数据。
这是我的代码:
func mutateNetwork(){
let conCount = currentWorkflowHolder.workflowData[currentWorkflowHolder.workflowData.count-1][currentWorkflowHolder.workflowData[currentWorkflowHolder.workflowData.count-1].count-1].thirdConnections.count-1
for _ in 0...50{
let arg1 = Int.random(in: 0...conCount)
let arg2 = Int.random(in: 0...currentWorkflowHolder.workflowData[currentWorkflowHolder.workflowData.count-1][currentWorkflowHolder.workflowData[currentWorkflowHolder.workflowData.count-1].count-1].thirdConnections[conCount].count)
currentWorkflowHolder.workflowData[0][0].thirdConnections[arg1][arg2] = Float.random(in: -50...50)
}
}
由于我试图消除潜在的问题,所以有点混乱。
我已经尝试过:
autoreleasepool{}
,但没有帮助编辑: currentWorkflowHolder 是一个属性,但它没有 get{} 或 set{}。
它仅更改数据,不会创建事后需要存储的新数据。
这可能并不像您想象的那样。这段代码几乎肯定会进行大量的分配和复制。该代码的高度简化版本是:
xs[1][2] = 4
这不是一个“二维数组”,您只是修改其中的单个元素。这是一个数组的数组,您正在修改嵌套数组 和 包含数组。它的工作原理大致如下:
var row = xs[1]
row[2] = 4 // This is **very** likely to make a copy of all of row.
xs[1] = row // This will probably make a copy of all of xs.
考虑到这里发生的所有嵌套,您几乎肯定会复制所有内容的副本。这些最终都应该被释放,这样这只代表短期内存峰值和非常糟糕的性能。
当您说“数据不会被释放”时,您如何检查这一点?如果您只是查看报告的总内存使用情况,这是正常的。当你的程序分配内存然后释放它时,如果没有内存压力,它可能不会立即返回到操作系统。这是一种优化,因为从操作系统请求内存是昂贵的,并且系统假设如果您请求一次,您可能会再次需要它。 Instruments 中的分配工具通常是检查内存使用情况的更好方法。 Xcode 的内存“仪表板”通常也非常适合此目的。但像活动监视器这样的东西可能会产生极大的误导。
解决此问题的方法是重新设计数据存储。作为一个起点,如果这实际上是一个矩阵而不是任意长度数组的数组,那么实现它的正确方法是一个单一的平面数组,您可以通过将行乘以宽度来计算索引,然后添加列(或反之亦然,具体取决于您想要的顺序)。