• iOS 堆栈的溢出


    一般情况下应用程序是不需要考虑堆和栈的大小的,总是当作足够大来使用就能满足一般业务开发。但是事实上堆和栈都不是无上限的,过多的递归会导致栈溢出,过多的 alloc 变量会导致堆溢出。

    例子

    不得不说 Cocoa 的内存管理优化做得挺好的,单纯用 C++ 在 Mac 下编译后执行以下代码,递归 174671 次后挂掉:

    #include <iostream>
    #include <stdlib.h>
    
    void test(int i) {
        void* ap = malloc(1024);
        std::cout << ++i << "
    ";
        test(i);
    }
    
    int main() {
        std::cout << "start!" << "
    ";
        test(0);
        return 0;
    }
    

    而在 iOS 上执行以下代码则怎么也不会挂,连 memory warning 都没有:

    - (void)stackOverFlow:(int)i {
    
        char * aLeak = malloc(1024);
    
        NSLog(@"try %d", ++i);
        [self stackOverFlow:i];
    }
    

    而且如果 malloc 的大小改成比 1024 大的如 10240,其内存占用的增长要远慢于 1024。这大概要归功于 Cocoa 的 Flyweight 设计模式,不过暂时还没能真的理解到其优化原理,猜测可能是虽然内存空间申请了但是一直没用到,针对这种循环 alloc 的场景,做了记录,等到用到内存空间了才真正给出空间。

    原理

    iOS 内存布局如下图所示:

    image

    在应用程序分配的内存空间里面,最低地址位是固定的代码段和数据段,往上是堆,用来存放全局变量,对于 ObjC 来说,就是 alloc 出来的变量,都会放进这里,堆不够用的时候就会往上申请空间。最顶部高地址位是栈,局部的基本类型变量都会放进栈里。 ObjC 的对象都是以指针进行操控的,局部变量的指针都在栈里,全局的变量在堆里,而无论是什么指针,alloc 出来的都在堆里,所以 alloc 出来的变量一定要记得 release。

    对于 autorelease 变量来说,每个函数有一个对应的 autorelease pool,函数出栈的时候 pool 被销毁,同时调用这个 pool 里面变量的 dealloc 函数来实现其内部 alloc 出来的变量的释放。

  • 相关阅读:
    Linux:备份
    在 Cordova/Phonegap for Android 中包含中文文件名的页面
    jQuery插件开发
    为Google Reader守夜。。。
    冒泡排序
    无题六月
    XXX读后感
    KL25的AD采集操作
    工作流--JBPM简介及开发环境搭建
    内存错误:CRT detected that the application wrote to memory after end of heap buffer
  • 原文地址:https://www.cnblogs.com/wuwangchuxin/p/3682538.html
Copyright © 2020-2023  润新知