04 OC内存管理

194 阅读5分钟

目录:

  1. 预备知识—程序的内存分配
  2. 示例代码
  3. 全局变量、局部变量、静态全局变量、静态局部变量在内存中如何存储,有什么区别
  4. 堆和栈再分配方式的不同
  5. 为什么要管理内存
  6. 内存管理方式

1. 预备知识—程序的内存分配

一个由C/C++编译的程序占用的内存分为以下几个部分

  • 栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其
    操作方式类似于数据结构中的栈。
  • 堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回
    收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
  • 全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的
    全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另
    一块区域。 - 程序结束后由系统释放。
  • 文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
  • 程序代码区—存放函数体的二进制代码。

2. 示例代码

int a = 0;      // 全局初始化区
char *p1;      // 全局未初始化区

int main() {
    int b;            // 栈区
    char s[] = "abc"; // 栈区
    char *p2; // 栈区
    char *p3 = "123456"; // p3在栈区;   "123456\0" 在常量区,
    
    static int c =0;      // 全局(静态)初始化区
    p1 = (char *)malloc(10);
    p2 = (char *)malloc(20); // 分配得来的10和20字节的区域就在堆区
    strcpy(p1, "123456");    // "123456\0" 放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}

3. 全局变量、局部变量、静态全局变量、静态局部变量在内存中如何存储,有什么区别

从作用域上来区分:

  • **全局变量: **具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。
  • **局部变量: **也只有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。
  • **静态局部变量: **具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。
  • **静态全局变量: **也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。

从分配内存空间看:全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间。

从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。

总的来说,全局变量、局部变量、静态全局变量、静态局部变量的区别是

  • 生存周期不同
  • 作用范围不同
  • 分配方式不同

4. 堆和栈再分配方式的不同

栈: 由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间 堆: 需要程序员自己申请,并指明大小,在c中malloc函数 如p1 = (char *)malloc(10); 在C++中用new运算符 如p2 = (char *)new(10); 但是注意p1、p2本身是在栈中的。

5. 为什么要管理内存

iOS应用程序出现Crash(闪退),90%的原因是因为内存问题。
在一个拥有数十个甚至是上百个类的的工程里 ,查找内存问题极其困难,
学会内存管理,能帮我们 减少出错的机率。

内存问题体现在两个-----内存溢出、野指针异常

  • 内部溢出 iOS给每个应用程序分配了一定的内存,
    用于程序的运行。一旦超出内存上限,程序就会Crash。

  • 野指针异常 对象的内存已经被系统回收,但是仍然使用指针操作这块内存。
    野指针异常是程序Crash的重要原因之一。
    代码量越大程序越容易出现野指针问题。

6. 内存管理方式