内存的静态分配和动态分配的区别【转】

本文深入解析内存的静态分配与动态分配的区别,阐述了两者在时间、空间上的差异,以及它们在程序执行过程中的角色。详细解释了堆和栈的特性,动态内存分配的优势和挑战,以及如何使用malloc和free函数有效管理内存,避免内存泄漏。

来源: <http://blog.youkuaiyun.com/liuchao1986105/article/details/6724392>

内存的静态分配和动态分配的区别主要是两个

      一是时间不同。静态分配发生在程序编译和连接的时候。动态分配则发生在程序调入和执行的时候。

      二是空间不同。堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由函数malloc进行分配。不过栈的动态分配和堆不同,他的动态分配是由编译器进行释放,无需我们手工实现。    

    对于一个进程的内存空间而言,可以在逻辑上分成3个部份:代码区静态数据区动态数据区

    动态数据区一般就是“堆栈”。“栈(stack)”和“堆(heap)”是两种不同的动态数据区,栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”,所以每个线程虽然代码一样,但本地变量的数据都是互不干扰。一个堆栈可以通过“基地址”和“栈顶”地址来描述。全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。程序通过堆栈的基地址和偏移量来访问本地变量。

 

    一般,用static修饰的变量,全局变量位于静态数据区。函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。

 

    所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。
    例如我们定义一个float型数组:

        float score[100];   

    但是,在使用数组的时候,总有一个问题困扰着我们:数组应该有多大?在很多的情况下,你并不能确定要使用多大的数组,比如上例,你可能并不知道我们要定义的这个数组到底有多大,那么你就要把数组定义得足够大。这样,你的程序在运行时就申请了固定大小的你认为足够大的内存空间。即使你知道你想利用的空间大小,但是如果因为某种特殊原因空间利用的大小有增加或者减少,你又必须重新去修改程序,扩大数组的存储范围。这种分配固定大小的内存分配方法称之为静态内存分配。但是这种内存分配的方法存在比较严重的缺陷,特别是处理某些问题时:在大多数情况下会浪费大量的内存空间,在少数情况下,当你定义的数组不够大时,可能引起下标越界错误,甚至导致严重后果。 
    我们用动态内存分配就可以解决上面的问题. 所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。从以上动、静态内存分配比较可以知道动态内存分配相对于景泰内存分配的特点: 
   1、不需要预先分配存储空间;
   2、分配的空间可以根据程序的需要扩大或缩小。 
    要实现根据程序的需要动态分配存储空间,就必须用到malloc函数.
    malloc函数的原型为:void *malloc (unsigned int size) 其作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。还有一点必须注意的是,当函数未能成功分配存储空间(如内存不足)就会返回一个NULL指针。所以在调用该函数时应该检测返回值是否为NULL并执行相应的操作

    静态内存是在程序一开始运行就会分配内存,直到程序结束了,内存才被释放。
    动态内存是在程序调用在程序中定义的函数时才被分配,函数调用结束了,动态内存就释放。

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

static int a;      /* 这是定义了一个静态的变量 */

int     a;      /* 这是定义了一个动态的变量; */

/* 静态内存可以用于求阶层。 */

/ 例如 :

jiechen( int i )

{

    static int a = 1;

    for (; a <= i, a++ )

        return(a * i);

}

#include "stdio.h"

main()

{

    int a, i;

    printf( "enter number:" )

    scanf( "%d", &a );

    for ( i = 1; i <= a; i++ )

        printf( "i!=%d\n", jiechen( i ) );

}

 

    运行
    输入3
    结果为

1 ! = 1

2 ! = 2

3 ! = 3

 

 

    malloc系统函数分配的内存就是从堆上分配内存。从堆上分配的内存一定要自己释放。用free释放,不然就是术语——“内存泄露”(或是“内存漏洞”)—— Memory Leak。于是,系统的可分配内存会随malloc越来越少,直到系统崩溃。还是来看看“栈内存”和“堆内存”的差别吧。

    栈内存分配

1

2

3

4

5

6

    char*

    AllocStrFromStack()

    {

        char pstr[100];

        return pstr;

    }

   
    堆内存分配

1

2

3

4

5

6

7

8

char* AllocStrFromHeap( int len )

{

    char *pstr;

 

    if ( len <= 0 )

        return(NULL);

    return( ( char * ) malloc( len ) );

}

    

    对于第一个函数,那块pstr的内存在函数返回时就被系统释放了。于是所返回的char*什么也没有。而对于第二个函数,是从堆上分配内存,所以哪怕是程序退出时,也不释放,所以第二个函数的返回的内存没有问题,可以被使用。但一定要调用free释放,不然就是Memory Leak!

    在堆上分配内存很容易造成内存泄漏,这是C/C++的最大的“克星”,如果你的程序要稳定,那么就不要出现Memory Leak。所以,我还是要在这里千叮咛万嘱付,在使用malloc系统函数(包括calloc,realloc)时千万要小心。

    记得有一个UNIX上的服务应用程序,大约有几百的C文件编译而成,运行测试良好,等使用时,每隔三个月系统就是down一次,搞得许多人焦头烂额,查不出问题所在。只好,每隔两个月人工手动重启系统一次。出现这种问题就是Memery Leak在做怪了,在C/C++中这种问题总是会发生,所以你一定要小心。一个Rational的检测工作——Purify,可以帮你测试你的程序有没有内存泄漏。

    我保证,做过许多C/C++的工程的程序员,都会对malloc或是new有些感冒。当你什么时候在使用malloc和new时,有一种轻度的紧张和惶恐的感觉时,你就具备了这方面的修养了。

对于malloc和free的操作有以下规则:

1) 配对使用,有一个malloc,就应该有一个free。(C++中对应为new和delete)

2) 尽量在同一层上使用,不要像上面那种,malloc在函数中,而free在函数外。最好在同一调用层上使用这两个函数。

3) malloc分配的内存一定要初始化。free后的指针一定要设置为NULL。    


注:虽然现在的操作系统(如:UNIX和Win2k/NT)都有进程内存跟踪机制,也就是如果你有没有释放的内存,操作系统会帮你释放。但操作系统依然不会释放你程序中所有产生了Memory Leak的内存,所以,最好还是你自己来做这个工作。(有的时候不知不觉就出现Memory Leak了,而且在几百万行的代码中找无异于海底捞针,Rational有一个工具叫Purify,可能很好的帮你检查程序中的Memory Leak)

 

    第一个例子也讲得不清楚。所谓系统释放,应该是指系统在自己的表里把这段内存标记为可以使用,以后可以被别的程序使用,所以第一个例子会造成程序能访问到已经释放的内存空间,是越界,会造成不可预测的情况。
    系统一般不会自动去清除释放空间内的数据,而是由以后的程序来覆盖。所以很多程序开头都会做MEMSET(...) ,就是为了防止这种垃圾数据的情况。
    如果在程序运行中要改变内存块的大小,可以用RALLOC()函数,它能在原来地址上重新分配一块空间,不过是用的时候要小心,也是比较容易出问题

 

C语言中内存静态分配动态分配是两种不同的内存管理方式,它们在原理、区别使用方法上各有特点。 ### 原理 - **静态分配**:在编译时就为变量分配内存空间,这些内存空间的大小位置在程序运行期间是固定不变的。静态分配内存位于全局数据区或栈区。例如,全局变量静态变量在编译时就被分配了固定的内存地址,程序不结束,这些内存不会被销毁;而局部变量在函数调用时在栈上分配内存,函数结束时,栈上的内存会自动被回收 [^4]。 - **动态分配**:在程序运行过程中,根据实际需要向操作系统请求分配内存空间,这些空间位于堆区。当程序不再使用这些内存时,需要手动将其释放,归还给操作系统。动态分配可以根据程序运行时的实际情况灵活地调整内存的使用量 [^3]。 ### 区别 - **分配时间**:静态分配在编译时完成,而动态分配在程序运行时进行 [^3][^4]。 - **内存位置**:静态分配内存通常在全局数据区或栈区,而动态分配内存位于堆区 [^3][^4]。 - **生命周期**:静态分配内存生命周期与程序的运行周期相关,全局变量静态变量在程序结束时才释放,局部变量在函数结束时释放;动态分配内存需要手动管理,在不需要时要使用特定的函数(如`free`)来释放,否则会造成内存泄漏 [^4][^5]。 - **灵活性**:静态分配内存大小在编译时就已确定,无法在运行时改变;动态分配可以根据程序的实际需求在运行时调整内存的大小 [^3]。 ### 使用方法 - **静态分配** - **全局变量**:在函数外部定义的变量,在整个程序的生命周期内都存在。例如: ```c #include <stdio.h> // 全局变量 int globalVar = 10; int main() { printf("Global variable: %d\n", globalVar); return 0; } ``` - **静态局部变量**:使用`static`关键字修饰的局部变量,在函数调用结束后不会被销毁,下次调用函数时仍保留上次的值。例如: ```c #include <stdio.h> void func() { static int staticVar = 0; staticVar++; printf("Static variable: %d\n", staticVar); } int main() { func(); func(); return 0; } ``` - **普通局部变量**:在函数内部定义的变量,在函数调用时在栈上分配内存,函数结束时自动释放。例如: ```c #include <stdio.h> void func() { int localVar = 5; printf("Local variable: %d\n", localVar); } int main() { func(); return 0; } ``` - **动态分配**:C语言提供了一些内存管理函数来实现动态内存分配,常用的函数有`malloc`、`calloc`、`realloc``free` [^2]。 - **`malloc`**:用于分配指定大小的内存空间,返回一个指向该内存空间的指针。例如: ```c #include <stdio.h> #include <stdlib.h> int main() { int *ptr; // 分配40字节的内存空间 ptr = (int *)malloc(40); if (ptr == NULL) { printf("Memory allocation failed\n"); return 1; } // 使用内存 for (int i = 0; i < 10; i++) { ptr[i] = i; } // 释放内存 free(ptr); ptr = NULL; return 0; } ``` - **`calloc`**:用于分配指定数量大小的内存空间,并将其初始化为0。例如: ```c #include <stdio.h> #include <stdlib.h> int main() { int *ptr; // 分配10个int类型的内存空间,并初始化为0 ptr = (int *)calloc(10, sizeof(int)); if (ptr == NULL) { printf("Memory allocation failed\n"); return 1; } // 使用内存 for (int i = 0; i < 10; i++) { printf("%d ", ptr[i]); } // 释放内存 free(ptr); ptr = NULL; return 0; } ``` - **`realloc`**:用于调整已分配内存的大小。例如: ```c #include <stdio.h> #include <stdlib.h> int main() { int *ptr; // 分配10个int类型的内存空间 ptr = (int *)malloc(10 * sizeof(int)); if (ptr == NULL) { printf("Memory allocation failed\n"); return 1; } // 调整内存大小为20个int类型的空间 ptr = (int *)realloc(ptr, 20 * sizeof(int)); if (ptr == NULL) { printf("Memory reallocation failed\n"); return 1; } // 释放内存 free(ptr); ptr = NULL; return 0; } ``` - **`free`**:用于释放动态分配内存空间。在使用`free`函数释放内存后,为了避免产生野指针,需要将指针置为`NULL` [^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值