JNI基础之C动态内存分配笔记

当我们在运行下面一段代码时,会抛出stack overflow的异常:

#include <stdio.h>

void main(){
	int i[1024 * 1024 * 10];

	getchar();
}

这个错误直译过来就是栈溢出,这里面就涉及到C语言的内存区域的分配问题。

C语言内存区域划分

1、栈区(stack) 先进后出的内存结构,所有的自动变量、函数形参都存储在栈中

  •  每个线程都有自己的栈帧

  •  栈内存尺寸固定,超过则引起栈溢出,如上面的代码:

  • 自动分配(申请方式如:int i[10];),变量离开作用域后自动释放

2、堆区 (heap)  和栈一样,也是一种在程序运行过程中可以随时修改的内存区域,但没有栈那样先进后出的顺序

  • 申请方式: int *p = malloc(1024);
  • 由程序员手动分配和释放,

  • 可分配约占操作系统80%内存


           3、全局、静态区

静态区存放程序中所有的全局变量和静态变量。


           4、字符常量区

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


           5、程序代码区

  • 程序被操作系统加载到内存的时候,所有的可执行代码(程序代码指令、常量字符串等)都加载到代码区

  • 这块内存在程序运行期间是不变的。

  • 代码区是平行的,里面装的就是一堆指令,在程序运行期间是不能改变的。

动态分配内存

1、malloc函数:向堆申请开启指定大小的内存区域

//分配40M内存
int* p = malloc(1024 * 1024 * 10 * sizeof(int));

2、realloc()函数:调整已分配的内存区域

//
int* p = malloc(100 * sizeof(int));

//发现内存不够用,重新分配内存;

int* p2 = realloc(p, sizeof(int) * 200);

3、free()函数:释放已分配的内存区域;

//开辟40M内存
int* p = malloc(1024 * 1024 * 10 * sizeof(int));
//释放
free(p)

区别:

静态内存分配创建数组,数组大小固定,必须在指定数组长度。

int i[3];
int ids[] = {10, 20, 22};

动态内存分配创建数组,开辟一段内存,然后在这段内存上赋值数组,在程序运行过程中,可以随意的开辟指定大小的内存以供使用,相当于java中的集合。

int len = 1024;    //指针长度
//开辟内存,1024*4个字节
int *p = malloc(len * sizeof(int));
int i = 0;
//给数组赋值
for(; i < len; i++){
    p[i] = rand();
}

静态内存分配,内存分配的大小是固定的,有以下问题

  1. 容易超出栈内存的最大值;
  2. 通常为了防止内存不够用,会开辟更多地内存,容易造成内存浪费

动态内存分配,在程序运行过程中动态指定需要使用的内存大小,手动释放,释放后这些内存还可以被重新利用。同时可以重新分配内存区域的大小

关于realloc重新分配内存:

1、缩小内存,即分配后的内存区域大小比原来的内存区域要小,则直接截去多余的内存,返回的指针和原来的指针指向              地址相同,返回原指针。

2、扩大内存:即分配后的内存区域要大于原内存大小。

(1)因为分配的内存是连续的,若当前指针后的内存区域后续内存端足够分配,则直接在后续的内存区域分配给当前指针,返回原指针。

(2)若当前指针后续内存区域不足以分配,则使用堆中第一块满足这一条件的内存块,并把当前的数据复制到新的内存块中,返回新的指向改内存块的指针,原内存块被释放。

(3)堆中内存不足,申请失败,返回NULL,原来的指针仍有效;

 内存分配的几个注意事项

  1. 内存不能重复释放,所以一般在释放前做一个NULL判断:
  2. 养成一个良好习惯,在释放掉一个内存后,并置为空NULL;
    if( p != NULL){
        free(p);
        //可以看到p仍有值
        printf("%#x\n", p);
        p = NULL;
    }
  3. 重复给一个变量调用malloc函数,要在合适的时机调用free,否则造成内存泄漏
     //第一次分配内存
     int *p = malloc(1024 * 10 * sizeof(int));
     //第二次分配内存
     p = malloc(1024 * 4 * sizeof(int));
     
     //释放内存
     free(p);
     

    这里调了一次free释放内存,然而调用了两次内存分配开辟了两段内存区域,第一次p指向了第一段内存区域,第二次指向了新分配的内存区域,调用了free释放的是第二段内存,则第一段内存仍没有得到释放,从而造成内存泄漏

猜你喜欢

转载自blog.csdn.net/u011598031/article/details/85003269