漫谈内存泄漏

前言

最近看了同事整理的一份与内存泄漏相关思维导图。突然想从内存泄漏的角度探讨一下与内存相关的话题。
什么是内存泄漏?然而我又问自己一个问题, malloc 的内存到底是什么?

什么是内存

在计算机系统中,我们谈论的内存通常是指DRAM

虚拟内存空间

而当我们程序在系统上运行起来时,操作系统为我们提供了一个假象,程序看起来是独占使用处理器、主存和I/O设备的。这种假象是通过进程的概念来实现的。

虚拟内存,也为进程提供一个假象,每个进程都独占地使用主存。每个进程看到的内存都是一致的,称为虚拟内存空间

虚拟内存的能力:

  • 使主存中只保存活动区域,根据需要在磁盘和主存之间来回传输数据。
  • 为每个内存提供一致的地址空间。
  • 保护了每个进程的地址空间不被其他进程破坏。
一个 Linux 进程的虚拟内存.png

上图是一个 Linux 进程的虚拟内存。也就是说我们平时 malloc 得到的内存地址,其实是虚拟内存的地址。

动态内存分配

其实系统为我们提供了 mmapmunmap 函数来创建和删除虚拟内存的区域。但很多时候直到程序实际运行才知道某些数据结构的大小。所以就有了动态内存分配器。

动态内存分配器有两种基本类型:

  • 显式分配器,需要显式释放。例如 C 和 C++ 。
  • 隐式分配器,分配器检测已分配何时不再被程序所使用,那么就释放这个块。例如 Lisp、Java 等。

什么是内存泄漏

内存泄漏是常见的内存错误之一。我们知道 malloc 其实是从虚拟内存空间的堆中申请空闲的地址的。然而内存空间是有限的。程序在运行中 malloc 出来的内存空间使用完后,没有被 free 掉,这样我们就称之为内存泄漏

ARC 机制

iOS 上,不论是 Objective-C 还是 Swift 都是使用引用计数式的内存管理方式。
ARC 就是 Automatic Reference Counting, 其实 ARC 很简单,我们只需要弄清楚对象之间的持有关系。

举个简单的例子:

场景一

self.textField.text = @"Sim";

下图简单的描述了,这段代码对象之间的持有关系。 self.textField.text 持有着 @"Sim"@"Sim" 对象的 retainCount = 1。

1.png
self.textField.text = @"SimCai";

这时,对象 @"Sim" 不再被 self.textField.text 持有,所以 @"Sim" 对象的 retainCount = 0,对象会被释放掉。

2.png

场景二

self.textField.text = @"Sim";
NSString *firstName = self.textField.text;

这段代码,@"Sim" 对象被 firstNameself.textField.text 同时持有。所以 @"Sim" 对象的 retainCount = 2 。

3.png
self.textField.text = @"SimCai";

这时 self.textField.text 不再持有 @"Sim" 对象,但是 firstName 依然持有 @"Sim" ,所以 @"Sim" 的 retainCount = 1 ,不会被释放。

4.png

直到 firstName 也不再持有 @"Sim" 对象,@"Sim" 才会被释放。

5.png

循环引用

ARC 整套机制看起来很简单,但会不会有什么特例,会造成内存无法被正常释放呢?
有,循环引用

ViewController 持有 TableView,同时 TableView 也持有 ViewController 。 他们相互有引用关系。这就是循环引用

6.png

为了打破这种引用的循环。我们可以通过 weak (弱引用) 来解决这个问题。

一般情况下,ViewController 是会被个 UINavigationController 所持有。如果 TableView 也持有 ViewController ,这时 ViewController 的 retainCount = 2。

而我们对 self.vc 使用了 weak 后,self.vc = ViewController ,这样的操作,不再会导致 retainCount 加1 。 这时 ViewController 依然还是 retainCount = 1。

7.png

而当 ViewController 被释放后 self.vc 建会指向 nil 。当然在这个例子,在 ViewController 释放后,TableView 自然也会别释放。

8.png

但在一些场景下使用 weak 需要比较注意的。例如,一个全局的定时器,如果持有了 ViewController 是弱引用。 那当 ViewController 被释放后,定时器再去访问 ViewController 就将引起 crash 。

常见的内存泄漏场景

  • 使用时 block (需要格外小心)
  • NSTimer 没有销毁
  • KVO 没有移除
  • NSNotification 没有移除

当了解了 ARC 后,再我看来这些本质都是循环引用问题(当然还有一些 CF 的API,还是需要手动内存管理的)。

  • block 会捕获变量
  • NSTimer 需要持有对象,进行通知回调
  • KVO 需要持有对象,进行通知回调
  • NSNotification 需要持有对象,进行通知回调

所以这些操作都容易造成内存泄漏。

要避免内存泄漏,更重要的是需要了解 ARC 的机制。实际上,可能造成内存泄漏的场景还有很多。

总结

  • malloc 得到的内存地址,实际是虚拟内存空间中的堆地址。并不是实际的物理地址。
  • 内存泄漏是指,内存资源没用了,但内存资源没被 free。(用完了,就别占着坑)
  • 在 iOS ARC 时代,大部分内存泄漏问题,是由循环引用造成的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • 内存管理 简述OC中内存管理机制。与retain配对使用的方法是dealloc还是release,为什么?需要与a...
    丶逐渐阅读 1,946评论 1 16
  • 1.1 什么是自动引用计数 概念:在 LLVM 编译器中设置 ARC(Automaitc Reference Co...
    __silhouette阅读 5,076评论 1 17
  • 1.远古时代的故事那些经历过手工管理内存(MRC)时代的人们,一定对 iOS 开发中的内存管理记忆犹新。那个时候大...
    MissHector阅读 206评论 0 1
  • 内存管理是程序在运行时分配内存、使用内存,并在程序完成时释放内存的过程。在Objective-C中,也被看作是在众...
    蹲瓜阅读 2,991评论 1 8
  • 初高中英语教科书中大概还会介绍一部根据小说改编的同名电影<Gone with wind>, 小说的中文译名是《飘》...
    _levi阅读 352评论 4 2