ios内存管理深入解析

内存

今天我们来对copy,retain,assign来一个比较深刻的认识,弄明白为什么要这么做!数据乃以生存的基础那就是内存。

内存区域

 有人认为三种,也有人认为四种,还有人认为是五种,我相信他们都有道理,没必要深究。这里以五种为例,其实我们只需要知道前面三个就够了。

1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放 , 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。

3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态 变量在一块区域,
未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(BSS)。 - 程序结束后由系统释放

4、文字常量区 — 常量字符串就是放在这里的。 程序结束后由系统释放

5、程序代码区— 存放函数体的二进制代码。

  • stack
    1. 一组数据的存放方式,特点为LIFO,即后进先出(Last in, first out)。
    2. call stack,也就是调用栈,表示函数像堆积木一样存放,以实现层层调用
class Student{
    int age;              
    String name;      

    public Student(int Age, String Name)
    {
        this.age = Age;
        setName(Name);
    }
    public void setName(String Name)
    {
        this.name = Name;
    }
}

public class Main{
    public static void main(String[] args) {
            Student s;           
            s = new Student(23,"Jonh");
    }
}

首先调用main方法,里面需要生成一个Student的实例,于是又调用Student构造函数。在构造函数中,又调用到setName方法。这三次调用像积木一样堆起来,程序运行的时候,总是先完成最上层的调用,然后将它的值返回到下一层调用,直至完成整个调用栈,返回最后的结果。Stack frame(堆栈帧)是一个为函数保留的区域,用来存储关于参数、局部变量和返回地址的信息。堆栈帧通常是在新的函数调用的时候创建,并在函数返回的时候销毁。
3. 存放数据的一种内存区域,程序运行的时候,需要内存空间存放数据。一般来说,系统会划分出两种不同的内存空间:一种叫做stack(栈),另一种叫做heap(堆)。它们的主要区别是:stack是有结构的,每个区块按照一定次序存放,可以明确知道每个区块的大小;heap是没有结构的,数据可以任意存放。因此,stack的寻址速度要快于heap。其他的区别还有,一般来说,每个线程分配一个stack,每个进程分配一个heap,也就是说,stack是线程独占的heap是线程共用的。此外,stack创建的时候,大小是确定的,数据超过这个大小,就发生stack overflow错误,而heap的大小是不确定的,需要的话可以不断增加。

public void Method1()
{
    int i=4;

    int y=2;

    class1 cls1 = new class1();
}
上面代码的Method1方法,共包含了三个变量:i, y 和 cls1。其中,i和y的值是整数,内存占用空间是确定的,而且是局部变量,只用在Method1区块之内,不会用于区块之外。cls1也是局部变量,但是类型为指针变量,指向一个对象的实例。指针变量占用的大小是确定的,但是对象实例以目前的信息无法确知所占用的内存空间大小。
![这里写图片描述](http://image.beekka.com/blog/201311/bg2013112905.jpg)
接下来的问题是,当Method1方法运行结束,会发生什么事?

回答是整个stack被清空,i、y和cls1这三个变量消失,因为它们是局部变量,区块一旦运行结束,就没必要再存在了。而heap之中的那个对象实例继续存在,直到系统的垃圾清理机制(garbage collector)将这块内存回收。因此,一般来说,内存泄漏都发生在heap,即某些内存空间不再被使用了,却因为种种原因,没有被系统回收。
下面看看变量具体分布实例:

using namespace std;

static int a=1;//全局初始化区 
int b=2;//全局初始化区 
char *p;//全局未初始化区 
char *p2;//全局未初始化区 
int *p3;//全局未初始化区 
int *p4;//全局未初始化区 
char *p5={"555555555"};//全局初始化区 
 main(){
    static int c=3;
    int d=4;//内存栈
    int e=7;//内存栈

    char *p6={"555555555"};
    p=(char*)malloc(sizeof(char)*10);//内存堆
    p2=(char*)malloc(sizeof(char)*10);//内存堆
    p3=(int*)malloc(sizeof(int));//内存堆
    p4=(int*)malloc(sizeof(int)*10);//内存堆
    for(int i=0;i<=9;i++)p4[i]=0x1;


    *p3=0x123;
    strcpy(p,"123456789");//文字常量区
    strcpy(p2,"987654321");
    strcpy(p2,"123456789");
}

这里写图片描述
1.可以看到全局初始化区与全局(静态)初始化区是在同一段内存 连续分配的,按内存地址增长方向分配

2.全局初始化区与全局未初始化区不在同一段内存区,全局初始化区好像按内存地址增长方向分配,全局未初始化区好像按内存增长的方向貌似没有规律!!

3.可以看到栈空间也是同一段内存 连续分配的,按内存地址减小方向分配

4.可以看到堆空间也是同一段内存 连续分配的,按内存地址增大方向分配

5.文字常量区在自己特有的内存段内,且有机制控制字符常量不被修改(当字符串相同的时候,系统有时还会将两个指针指向同一处)

注意 :在文字常量区的字符串不可以被修改,而在内存堆空间的字符串可以被修改!!

下面介绍函数参数压栈顺序:

void func(int k,char * sz,int b)
{
 return;
}

void main(void)
{
    int i = 0x22222222;
    char szTest[] = "abcd";
    int fb = 0x11111111;
    func(i,szTest,fb);
}

第一,参数压栈的顺序是从右到左,对应到上面的代码也就是先压b,然后是sz,最后是k。 第二,栈空间是从高地址向低地址发展的。

所以,我们可以估计出他们在内存中的分布,从高地址到低地址的顺序是:b, sz,k。 同时由于三个参数都占4个字节大小,所以两个参数的首地址之间相隔四个字节。

运行上述程序,动态观察三个变量的内存分布如下:

变量b在内存中的地址为:&b = 0x0025fa90

变量sz在内存中的地址为:&sz = 0x0025fa8c

变量k在内存中的地址为:&k = 0x0025fa88

上述地址印证了我们的说法。

另外,栈中的sz存储的是什么呢? 对了,就是主函数中的char 数组的首地址。观察内存,我们看到szTest的首地址为:0x0025fb40, 所以,sz的值就应该是0x0025fb40

,通过查看内存变量,发现事实就是如此。

待续
参考:

http://www.cnblogs.com/huhuuu/p/3440187.html
http://www.ruanyifeng.com/blog/2013/11/stack.html
http://blog.csdn.net/wealoong/article/details/8686353

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值