美文网首页iOS进阶之路
iOS:栈、堆、字符串常量区、全局区

iOS:栈、堆、字符串常量区、全局区

作者: 康小曹 | 来源:发表于2019-01-19 13:20 被阅读128次

C语言的数据在运行之前,编译器会提前预留一些内存(text 代码区,BSS、data等),这些数据不是说编译器就能生成,而是告诉程序在程序启动时先创建并分配内存,这部分数据就是全局区。程序运行之后也会生成堆区,堆区可以很大,用处也很多。其中一个作用就是作为栈使用。也就是遵循FIFO的内存,栈区内存由编译器控制,可以理解成编译器自动帮忙生成分配销毁内存的代码,栈区主要是用来存储局部变量和形参。堆区是程序员主动分配的内存。

一、常量区

常量区很多时候也被叫做:全局区/静态数据区/常量区等等。常量区分为两部分,已初始化的常量区和未初始化的常量区(也叫BSS,使用0初始化)存储的数据有

  • 全局变量(值可以在运行时被动态修改)
  • 静态变量(static修饰的变量,包括静态局部变量,静态全局变量)
  • 字符串常量(字符串常量因为可能在程序中多次被使用,所以在程序运行之前就会提前分配内存)

字符串常量的意义:
首先,字符串常量的意义就是在常量区存储一些已经使用了的,且没有指向的字符串常量。比如说一个char *p = "abcde";这个时候赋值给p的是"abcde"首个元素的地址。而char s[] = "abcde";是在内存中创建了"abcde"并赋值给了s[],也就是说s[]的内存中记录的就是"abcde",而p中内存记录的是地址,这也就导致了第二种情况下"abcde"无处安放,所以就存储在常量区。另外,排除编译器设置,按照C语言的原始设计思想,如果有char *p1 = "abc"; char *p2 = "abc";这种情况下,应该在常量区分配两块不同的内存,而有的编译器做了优化,所以会导致p1和p2指向的内存地址是一样的,也就是说"abc"=="abc" = YES;所以,不再需要纠结字符串常量到底存储在哪,只需要记住C语言中变量的赋值原则:非指针变量,拷贝内存中的表现形式(实际的值),指针变量,拷贝内存地址。
参考

例子1🌰:
代码:

char string1[] = "abcdef"; // string1在常量区/全局区

int main() {
    @autoreleasepool {
        char *p = "abcdef"; // abcdef在常量区/全局区
        printf("%p\n",&"abcdef");
        printf("%p\n",p); // 验证是否p指针指向是常量区"abcdef"
        printf("%p\n",string1); // 验证虽然同出常量区,但是string1并不是指向了"abcdef",而是复制或者说是重新生成

        char s[] = "abcdef";
        printf("%p\n",s); // s[]第一个元素的内存地址
        printf("%c\n",*s); // 获取s[]的第一个元素的值
        printf("%p\n",&(*s)); //验证s[]的值是否指向常量区的"abcdef",结果证明不是指向而是复制/重新生成
}

输出:

0x101f54b6d
0x101f54b6d
0x101f56188
0x7ffeedcae3e1
a
0x7ffeedcae3e1

最终结果:


image.png

例子2🌰:常量字符串不可改变
代码:

int main() {
    @autoreleasepool {
        char string2[] = "abc"; // abc存储在栈中
        char *p = "abc"; // "abc"存储在常量区
//        *p = '1'; //崩溃,常量区的值不可改变(那为什么全局变量的值可以改变?)
        char *p2 = string2;
        *p2 = '1'; //可以改变,因为string2是局部变量而不是字符串常量
//        string2 = '1'; // 编译报错(Array type 'char [4]' is not assignable),因为string2是一个地址,地址不能改变

        printf("%s",string2);
}

结果:

1bc

二、堆

堆区(heap):是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程,C/C++分别用malloc/New请求分配Heap,用free/delete销毁内存。由于从操作系统管理的内存分配所以在分配和销毁时都要占用时间,所以用堆的效率低的多!但是堆的好处是可以做的很大,C/C++对分配的Heap是不初始化的,存放的数据类型有:

  • 程序员使用内存分配方法生成的变量

三、栈

栈(Stack):也叫堆栈,是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有FIFO的特性,在编译的时候可以指定需要的Stack的大小,也只能指定大小,因为内存的分配是要等到程序执行之后才分配的。在编程中,例如C/C++中,所有的局部变量都是从栈中分配内存空间,实际上也不是什么分配,只是从栈顶向下用就行,在退出函数的时候,只是修改栈指针就可以把栈中的内容销毁,所以速度最快(堆是指程序运行时申请的动态内存,而栈只是指一种使用堆的方法)。栈中存储的数据类型是:

  • 局部非静态变量
  • 形参

四、代码区

五、几个注意点

1.字符串常量不是字符,因为字符的本质还是数字(int)

  1. 虽然字符串常量和全局变量/静态变量在同一块内存区域,但是并不意味着值相等的字符串所处的内存地址是一样的。或者可以说:字符串常量没有对应的名称时才会存储到字符串常量区
    总结:


    C语言中的内存

参考:

C语言中内存分配

相关文章

  • 19·iOS 面试题·什么是 ARC ?(ARC 是为了解决什么

    前言 对于 iOS 内存分区有:栈区、堆区、静态区、全局区、常量区、代码区。对于静态区、全局区、常量区、代码区,对...

  • 内存管理

    首先,内存分为:栈区、堆区、全局区/静态区(存放全局变量和static静态变量)、常量区(存放字符串常量)、代码区...

  • 谈谈内存分配

    内存分区: iOS中主要是栈区(stack)、堆区(heap)、全局区/静态区(staic) 、常量区、代码区; ...

  • iOS 内存基础知识及堆区和栈区的区别

    iOS内存区域大致分为;栈区,堆区,全局区(静态区),文字常量区,程序代码区 栈区 栈区(stack)由编译器自动...

  • 【iOS知识体系】OC内存管理

    内存5区域:代码区、常量区、静态区(全局区)、堆区、栈区 函数 字符串: 数组 对象: 都是在堆区 block: ...

  • iOS内存相关问题小结

    1.iOS内存 IOS 内存区主要可以划分为五个区,栈区、堆区、全局变量区、常量区、代码区。 栈区:系统负责内存管...

  • iOS内存分配:堆、栈、全局区、常量区、代码区

    前言 内容参考: iOS 内存分配 栈、堆、全局区、常量区、代码区 NSString存储管理--NSTaggedP...

  • iOS 内存简单介绍

    iOS内存管理 iOS内存分为5个区:栈区,堆区,全局区,常量区,代码区 栈区stack:这一块区域系统会自己管理...

  • iOS内存分配五大区:

    iOS内存分配五大区: 栈区,堆区,静态区(全局区),常量区,代码区 动态数据区一般就是”堆栈”,栈是线性结构,堆...

  • iOS底层原理:内存五大区

    在iOS中,内存主要分为栈区、堆区、全局区、常量区、代码区五大区域。如下图所示 栈区(Stack) 定义 栈是系统...

网友评论

    本文标题:iOS:栈、堆、字符串常量区、全局区

    本文链接:https://www.haomeiwen.com/subject/evmadqtx.html