Swiftpipe理内存
这个问题已经清理完毕,重要的信息转移到了下面的答案。
我有一些关于内存pipe理的问题。
我正在构build一个照片编辑应用程序。 所以保持内存使用率低是重要的。 另外我不会发布代码,因为在做一件特定的事情时我没有大的内存泄漏。 发生的一切,我只是失去了几个KB / MB。 而成千上万的代码行来find千字节是没有趣的;)
我的应用程序使用核心数据,很多cifilter的东西,位置和基础知识。
我的第一个看法只是一个tableview,花了我大约5mb的内存。 然后,您拍摄一些照片,应用一些filter,将其保存到核心数据,然后返回到第一个视图。
除了驱动第一个视图所需的数据之外,是否有可能真正摆脱内存中的所有内容? (这非常保存和真棒5MB)
或者即使你把所有东西都设置为零,总会有东西留下来。
奖金问题: UIImageJPEGRepresentation
和UIImagePNGRepresentation
之间的文件大小/ CPU负载有差异吗? 我知道你可以用JPEG方法设置压缩质量(在CPU / GPU上更难?)。
只是想尽一切办法减less内存压力。
更新:
有人指出,这个问题可能太模糊了。
我在某个时候遇到的问题如下:
- 在某些情况下,峰值内存使用率过高
- 导航到第二个视图控制器,并返回导致泄漏
- 编辑图像会导致内存泄漏。
- 将filter应用于超过4-5个图像导致内存不足导致崩溃,此时没有更多的内存泄漏。 (在仪器中validation)
这是所有的testing在iPhone 4s,而不是模拟器。
这里有一个meme来点亮这个网站的心情。
这个问题已经打开了很长时间,我现在有足够的信心去回答。
不同等级的MM:
硬件内存
在使用ARC的 Swift中,我们无法清理实际的硬件RAM。 我们只能让操作系统为我们做到这一点。 一部分是使用正确的代码( optionals
和weak
),另一部分是为操作系统创造时间来完成它的工作。
想象一下,我们有一个无限期地在所有线程上运行的函数。 它做一件事,加载一个图像,转换成黑/白,并保存。 所有的图像最大在几个MB的和该function没有创build软件内存泄漏。 由于图像没有设置的大小,并可能有不同的压缩,他们没有相同的足迹。 此function将永远崩溃您的应用程序。
此“硬件”内存泄漏是由于function始终占用下一个可用的内存插槽。
由于没有空闲时间,操作系统不介入“实际清理内存”。 在每个通行证之间延迟完全解决这个问题。
语言特定的MM
铸件
一些操作对记忆没有影响,另一些操作:
let myInt : Int = 1 Float(myInt) // this creates a new instance
尝试转换:
(myInt as Float) // this will not create a new instance.
引用types与值types| 类与结构
两者都有其优点和危险。
结构是内存密集的,因为它们是值types 。 这意味着它们在分配给另一个实例时复制它们的值,有效地使内存使用率翻倍 。 没有修复/解决这个问题。 这是什么使结构结构。
类没有这种行为,因为它们是引用types 。 分配时不会复制。 相反,他们创build另一个参考对同一个对象 。 ARC或自动引用计数是跟踪这些引用。 每个对象都有一个参考计数器。 每次分配时,它都会增加一个。 每次你设置一个对nil的引用时,封闭函数结束,或者封闭对象消失,计数器就会closures。
当计数器达到0时,对象被去初始化。
有一种方法可以防止实例的初始化,从而造成泄漏。 这被称为强参考循环 。
对弱点的好解释
class MyClass { var otherClass : MyOtherClass? deinit { print("deinit") // never gets called } } class MyOtherClass { var myclass : MyClass? deinit { print("deinit") // never gets called } } var classA : MyClass? = MyClass() // sorry about the force unwrapping, don't do it like this classA!.otherClass = MyOtherClass() classA!.otherClass!.myclass = classA // this looks silly but in some form this happens a lot classA = nil // neither the MyClass nor the MyOtherClass deinitialised and we no longer have a reference we can acces. Immortalitiy reached they have.
设一个参照weak
class MyOtherClass { weak var myclass : MyClass? deinit { print("deinit") // gets called } }
进出
函数捕获传递给它们的值。 但也可以将这些值标记为inout。 这允许您更改传递给函数的Struct而不复制Struct。 这可能会节省内存,这取决于你传递了什么以及你在函数中做了什么。
在不使用元组的情况下,这也是一个有多个返回值的好方法。
var myInt : Int = 0 // return with inout func inoutTest(inout number: Int) { number += 5 } inoutTest(&myInt) print(myInt) // prints 5 // basic function with return creates a new instance which takes up it's own memory space func addTest(number:Int) -> Int { return number + 5 }
函数式编程
状态是随时间变化的价值
函数式编程是面向对象编程的反面部分。 函数式编程使用不可变状态。
更多关于这里
面向对象编程使用具有变化/变异状态的对象。 而不是创build一个新的值,旧的值被更新。
function编程可以使用更多的内存。
在FP上的例子
选配
可选项允许您将事情设置为零。 这将降低类或取消初始化结构的引用计数。 设置为零是清理内存的最简单方法。 这与ARC联手。 一旦你将一个类的所有引用设置为零,它将会退出并释放内存。
如果您没有将实例创build为可选项,则数据将保留在内存中,直到封闭函数结束或封闭类取消为止。 你可能不知道什么时候会发生。 可选项可以让你控制多久的活着。
API MM
许多“内存泄漏”是由具有“清理”function的框架引起的,您可能没有调用它。 一个很好的例子是UIGraphicsEndImageContext()
上下文将留在内存中,直到这个函数被调用。 当创build上下文的函数结束时,或者当涉及的映像设置为nil时,它不会清除。
另一个很好的例子是closuresViewControllers。 把一个VC放到一个VC然后再继续下去也许是有意义的,但是这个segue实际上会创build一个VC。 后退不会破坏风险投资。 调用dismissViewControllerAnimated()
将其从内存中删除。
阅读课程参考,并仔细检查没有“清理”function。
如果您确实需要仪器来查找泄漏,请查看关于此问题的其他答案。
点击Xcode右上angular的应用程序名称。
点击popup菜单中的“编辑scheme”。
确保左侧select了“运行”,然后单击窗口顶部附近的诊断选项卡。
在“内存pipe理”标题下,勾选“启用Guard Malloc”
你可能也想尝试检查“logging”头下的“分布式对象”和“malloc栈”
更多的信息在后卫malloc,卫兵边缘和涂鸦可以在这里find。
希望这可以帮助!