首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >快速管理内存

快速管理内存
EN

Stack Overflow用户
提问于 2015-01-15 06:41:45
回答 2查看 31.3K关注 0票数 29

这个问题被澄清了,重要的信息移到了下面的答案。

我有一些关于内存管理的问题。

我正在构建一个照片编辑应用程序。因此,保持较低的内存使用率是很重要的。此外,我不打算发布代码,因为我没有一个大的内存泄漏时,做一件特定的事情。所有发生的事情我都失去了几个KB/MB。翻看成千上万行代码来寻找千兆字节是没有乐趣的;)

我的应用程序使用核心数据、大量的cifilter内容、位置和基本功能。

我的第一个视图只是一个表视图,它花费了我大约5mb的内存。然后你拍一些照片,应用一些过滤器,这个被保存到核心数据,然后你回到第一个视图。

是否有可能真正摆脱内存中的一切,除了驱动第一个视图所需的数据。(非常节省和可怕的5mb)

还是总会有什么东西留下,即使你把一切都设为零?

的额外问题:UIImageJPEGRepresentationUIImagePNGRepresentation之间的文件大小/ cpu负载是否存在差异?我知道您可以使用JPEG方法设置压缩质量(在cpu/gpu上更难)。

尽一切可能减少记忆压力。

更新:

有人向我指出,这个问题可能过于含糊。

我在某些时候遇到的问题如下:

  • 在某些情况下,峰值内存使用率过高。
  • 导航到第二个视图控制器并返回会导致泄漏。
  • 编辑图像会导致内存泄漏。
  • 将过滤器应用于超过4-5个图像会导致崩溃,因为内存不足,此时没有更多的内存泄漏。(在文书中核实)

这都是在iPhone 4s上测试的,而不是模拟器。

这里有一个迷因,目的是为了缓和一下这个网站上的情绪。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-10-20 03:42:16

这个问题已经开放了很长时间,我现在有足够的信心来回答它。

不同级别的MM:

硬件存储器

在使用ARC的Swift中,我们没有办法清理实际的硬件ram。我们只能让操作系统为我们做到这一点。一部分是使用正确的代码(optionalsweak),另一部分是为操作系统创建时间来完成它的工作。

假设我们有一个在所有线程上无限期运行的函数。它只做一件事,加载一个图像,转换成黑白并保存。所有图像最大值在几毫巴和功能创建没有软件内存泄漏。因为图像没有固定的大小,而且可能有不同的压缩,所以它们没有相同的占用空间。这个功能总是会使你的应用程序崩溃。

这个“硬件”内存泄漏是由函数总是占用下一个可用的内存槽造成的。

由于没有空闲时间,操作系统不会介入“实际清理内存”。在每次传递之间设置一个延迟完全解决了这一问题。

语言专用MM

铸造

有些操作不会对内存产生影响,而其他操作则会:

代码语言:javascript
复制
let myInt : Int = 1
Float(myInt) // this creates a new instance

试着用铸造代替:

代码语言:javascript
复制
(myInt as Float) // this will not create a new instance.

引用类型与值类型

两者都有各自的优势和危险。

结构是内存密集型的,因为它们是值类型。这意味着当分配给另一个实例时,它们会复制值,从而有效地将加倍内存使用量。没有解决这个问题的办法。这就是构造结构的原因。

类没有这种行为,因为它们是引用类型。他们在被分配的时候不会复制。相反,他们创建了,另一个引用到相同的对象。ARC或自动参考计数是跟踪这些引用的内容。每个对象都有一个引用计数器。每分配一次,它就上升一次。每次设置对0的引用时,封闭函数结束,或包围对象deinits,计数器就会下降。

当计数器命中0时,对象被重新初始化。

有一种方法可以防止实例重新初始化,从而造成泄漏。这被称为强参考周期。

弱的很好的解释

代码语言:javascript
复制
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的引用

代码语言:javascript
复制
class MyOtherClass {

    weak var myclass : MyClass?

    deinit {
        print("deinit") // gets called
    }
}

inout

函数捕获传递给它们的值。但也有可能将这些值标记为inout。这允许您更改传递给函数的结构,而无需复制结构。这可能会节省内存,这取决于传递的内容和函数中的操作。

这也是一种不用元组就有多个返回值的好方法。

代码语言:javascript
复制
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

}

函数式编程

状态是随时间变化的值。

函数式程序设计是面向对象程序设计的重要组成部分。函数式编程使用不变的状态。

有关此这里的更多信息

面向对象编程使用具有变化/变异状态的对象。不是创建新值,而是更新旧值。

函数编程可以使用更多的内存。

FP实例

选项

选项允许你把事情设为零。这将降低类的引用计数或去初始化结构。将事情设置为零是清理内存的最简单方法。这与ARC并驾齐驱。一旦您将一个类的所有引用设置为零,它就会删除它并释放内存。

如果您不创建一个可选实例,数据将一直保存在内存中,直到封闭函数结束或封闭类deinits为止。你可能不知道什么时候会发生这种事。选项让你控制什么东西能活多久。

API MM

许多“内存泄漏”是由框架造成的,该框架具有一个您可能没有调用的“清理”函数。一个很好的例子是UIGraphicsEndImageContext(),在调用这个函数之前,上下文将一直保存在内存中。当创建上下文的函数结束时,或者当所涉及的图像设置为零时,它不会清除。

另一个很好的例子是解雇ViewControllers。对于一个VC,然后返回一个VC,这可能是有意义的,但是segue实际上创建了一个VC。后背并不能摧毁VC。调用dismissViewControllerAnimated()将其从内存中删除。

阅读类引用并反复检查没有“清理”函数。

如果您确实需要仪器来查找漏洞,请查看这个问题的另一个答案。

票数 35
EN

Stack Overflow用户

发布于 2015-01-19 16:36:36

单击Xcode右上角的应用程序名称。

单击弹出菜单中的“编辑方案”。

确保在左侧选择“RUN”,然后单击窗口顶部附近的“诊断”选项卡。

在“内存管理”标题下,检查“启用保护Malloc”

您还可以尝试在“日志”标题下检查“分布式对象”和“malloc堆栈”。

更多关于守卫的信息,守卫边缘和涂鸦可以找到这里

希望这能帮上忙!

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27958012

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档