这个问题已经清理完毕,重要信息转移到下面的答案中。
我对内存管理有一些疑问。
我正在构建照片编辑应用。因此,保持低内存使用率非常重要。 此外,我不会发布代码,因为在执行某项特定操作时我没有大的内存泄漏。我只是失去了几个KB / MB的所有发生的事情。通过成千上万行代码来查找千字节并不好玩;)
我的应用程序使用核心数据,大量的过滤器,位置和基础知识。
我的第一个视图只是一个桌面视图,花了我大约5mb的内存。 然后你拍摄一些照片,应用一些过滤器,这会保存到核心数据然后你回到第一个视图。
除了驱动第一个视图所需的数据外,是否有可能真正摆脱内存中的所有内容。 (非常节省和令人敬畏的5mb)
或者即使你把所有东西都设置为零,总会留下一些东西?
奖金问题:
UIImageJPEGRepresentation
和UIImagePNGRepresentation
之间的文件大小/ cpu负载是否有差异?
我知道你可以用JPEG方法设置压缩质量(在cpu / gpu上更难?)。
尽可能通过各种方式减少记忆压力。
更新
有人向我指出,问题可能过于模糊。
我在某些时候遇到的问题如下:
P.s这是在iPhone 4s上测试的,而不是模拟器。
这里有一个模因可以减轻这个网站的情绪。
答案 0 :(得分:31)
这个问题已经开放了很长时间,现在我有足够的信心回答它。
硬件内存
在使用 ARC 的Swift中,我们无法清理实际的硬件RAM。我们只能让操作系统为我们做到这一点。一部分是使用正确的代码(optionals
和weak
),另一部分是为操作系统创造时间来完成它的工作。
想象一下,我们有一个无限期地在所有线程上运行的函数。它做了一件事,加载图像,转换为黑/白并保存。 所有图像最多只有几个mb,并且该功能不会产生软件内存泄漏。 由于图像没有设置大小并且可能具有不同的压缩,因此它们没有相同的占用空间。 此功能将始终使您的应用程序崩溃。
此“硬件”内存泄漏是由该功能始终占用下一个可用内存插槽引起的。
操作系统不介入“实际清理内存”,因为没有空闲时间。在每次传递之间设置延迟完全解决了这个问题。
<强>铸造强>
某些操作对内存没有影响,其他操作则:
let myInt : Int = 1
Float(myInt) // this creates a new instance
尝试转换:
(myInt as Float) // this will not create a new instance.
参考类型与价值类型|类与结构
两者都有其优点和危险。
结构是内存密集型的,因为它们是值类型。 这意味着他们在分配给另一个实例时复制其值,实际上将内存使用量增加一倍。 没有解决方法/解决此问题。这就是Structs Structs的成果。
类没有此行为,因为它们是引用类型。分配时不会复制。 相反,他们会为同一个对象创建另一个参考。 ARC 或自动引用计数是跟踪这些引用的内容。 每个对象都有一个引用计数器。每次分配时,它都会增加一个。每次设置对nil的引用,封闭的函数结束,或者封闭的对象取消,计数器就会关闭。
当计数器达到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 强>
函数捕获传递给它们的值。但也可以将这些值标记为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
}
功能编程
状态是随时间变化的价值
函数式编程是面向对象编程的对应部分。函数式编程使用不可变状态。
有关此here
的更多信息面向对象编程使用具有更改/变异状态的对象。不是创建新值,而是更新旧值。
功能编程可以使用更多内存。
<强>选配强>
Optionals允许您将thing设置为nil。这将降低Classes或deinitialise Structs的引用计数。将事物设置为nil是清理内存的最简单方法。这与ARC携手并进。一旦将Class的所有引用设置为nil,它将会释放并释放内存。
如果不创建实例作为可选项,则数据将保留在内存中,直到封闭函数结束或封闭类取消。您可能不知道何时会发生这种情况。可选项可让您控制多长时间保持活动状态。
许多&#34;内存泄漏&#34;是由框架引起的,它具有您可能未调用的“清理”功能。
一个很好的例子是UIGraphicsEndImageContext()
在调用此函数之前,Context将保留在内存中。当创建上下文的函数结束或者涉及的图像设置为nil时,它不会清理。
另一个很好的例子是解雇ViewControllers。切换到一个VC然后向后移动可能是有意义的,但segue实际上创建了一个VC。 segue back不会破坏VC。调用dismissViewControllerAnimated()
将其从内存中删除。
阅读课程参考资料并仔细检查没有“清理”功能。
如果您确实需要仪器查找泄漏,请查看此问题的其他答案。
答案 1 :(得分:6)
点击Xcode右上角的应用名称。
点击弹出菜单中的“编辑方案”。
确保在左侧选择“RUN”,然后单击窗口顶部附近的诊断选项卡。
在“内存管理”标题下,选中“启用Guard Malloc”
你可能还想尝试在'logging'标题下检查'distributed objects'和'malloc stack'
有关守卫malloc,防护边缘和涂鸦的更多信息可以找到here。
希望这有帮助!