跟我一起学习C(内存篇)

    上一小节 跟我一起学习C(指针篇1)介绍了指针的基本用法及原理,这章主要介绍C对内存分配的管理。写到这里大家自然会联想到JVM运行时的内存分配,C程序会不会也像JAVA一样类似的处理方式呢?
    
    JAVA内存管理

    每个JVM程序在启动时根据脚本参数设置内存大小。主要设置堆大小(-Xmx、-Xms设置)、非堆大小(-PermSize、-MaxPermSize),以及内存回收策略(并行UseParallelGC、并发CMS)。

    以并行回收为例:
    程序中new出来的对象存放在堆区。jconsole下截图
跟我一起学习C(内存篇)_第1张图片

    静态数据、字符串常量、class方法等存放在非堆区。
跟我一起学习C(内存篇)_第2张图片

    以上只是JVM存放数据的物理图,而实际程序运行时数据区涉及到(堆、栈、方法区、程序计数器),这些不在本章中介绍,但它们的数据就是存放在以上两个图中的。
    可见JAVA的内存是事先指定好的,如果我们程序中产生的对象不断增加,而GC又回收不了,达到或接近Xmx值时就会报Outofmemory。

    C内存管理

    C的处理方式和JAVA类似么?我们先不急着回答这个问题。来看看编译链接出来的目标文件格式。比如hello.c编译完成以后生成hello,来看一下其内部结构。
跟我一起学习C(内存篇)_第3张图片
    目标文件的大小为7944个字节,而源文件只有320字节。再看第二个红圈中的几个内容及对应解释:
  
    text(代码区):代码段由各个函数产生,函数的每一个语句将最终经过编绎和汇编生成二进制机器代码。

    data(数据区):程序中明确被初始化的全局变量、静态变量(包括全局静态变量和局部静态变量)和常量数据(如字符串常量)。

    bss(未初始化数据区):存放的是全局未初始化变量(包括静态和全局)

    dec(十进制大小):以上几部份内容的10进制之和
    hex(十六进制大小):以上几部份内容的16进制之和

    由此可见上图中运行时的内存是没有分配的,包括栈和堆的数据。栈数据主要是方法内的私有变量、方法参数、临时数据等。方法运行完后自动释放空间,而堆是由程序动态分配的大小,可动态扩张或缩减( 可以理解成java中new出来的对象,既然new一个对象,至少得知道这个对象要占多大空间,所以先分配空间,然后再往空间中设值,比如一个Person(包括姓名,身份证号)的结构体,就先开辟一个空间,这才可以装下姓名和身份证号[/size]),具体C中就表现为操作malloc和free函数。

使用malloc和free的例子。
   
void mallocTest(char *q, int size){
    q = (char *)malloc(size);  
    //往新申请的空间中设置字符串  
    strcpy(q, "hello world!!!");  
    printf("%s\n", q);  

}

int main() {
	char *ptr = NULL; 
	mallocTest(ptr, 128);
	free(ptr);
	return 0;
}

   
    虽然上面的程序运行没问题,但是内存泄露了,free(p)实际上是free(null),在mallocTest方法中申请的空间没有释放掉。其实这和传参是有关系的。mallocTest方法中指针本身的地址和ptr的本身地址是不一样的(说白了不是同一个变量,只是指针的值都指向null,这个地方和JAVA的传参一样,都是值传递;地址传递只是指针的值是一样的,而形参指针和实参指针本身的地址,实际是两个不同变量),q在mallocTest方法中最后是指向了新分配的空间。如下测试
  
void mallocTest(char *q, int size){
	printf("pointer2 ---->%p\n",&q);
	q = (char *)malloc(size);
	strcpy(q, "hello world!!");
	printf("%s\n", q);
}

int main() {
	char *ptr = NULL;
	printf("pointer1 ---->%p\n",&ptr);
	mallocTest(ptr, 128);
	free(ptr);
	return 0;
}

跟我一起学习C(内存篇)_第4张图片
      正确的写法
方法1:把函数中的指针返回出来,再赋值给主函数的指针。
char * mallocTest(char *q, int size){
	q = (char *)malloc(size);
	strcpy(q, "hello world!!");
	printf("%s\n", q);
	return q;
}

int main() {
	char *ptr = NULL;
	ptr = mallocTest(ptr, 128);
	free(ptr);
	return 0;
}


方法2:使用二级指针,在mallocTest中改变一级指针的值,一级指针指向新申请的空间地址。
void mallocTest(char **q, int size){
	*q = (char *)malloc(size);
	strcpy(*q, "hello world!");
	printf("%s\n", *q);
}

int main() {
	char *ptr = NULL;
	mallocTest(&ptr, 128);
	free(ptr);
	return 0;
}

你可能感兴趣的:(内存)