堆内存的介绍及应用(含例子)

一、什么是堆内存

是进程的一个内存段(text\data\bss\heap\stack),由程序员手动管理
优点:足够大,
缺点:使用麻烦

二、为什么要使用堆内存

1、随着程序的复杂,数据量变多
2、其它内存的申请、释放不受控制,堆内存的申请、释放受控制,可以适时的节约内存

三、如何使用堆内存

注意:C语言中没有控制堆内存的语句,只能使用C标准库中的函数
#include<stdlib.h>

  1. 例如:void *malloc(size_t size);
    功能:从堆内存中申请size个字节的内存,申请到内存中数据的值不确定
    返回值:成功返回申请到的连续内存的首地址,失败返回NULL
  2. void free(void ptr);
    功能:释放一块堆内存 ptr: 要释放的堆内存的首地址 注意:free释放只是使用权,数据不会全部清理 不能连续释放,但是可以释放NULL
  3. void *calloc(size_t nmemb,size_t size);
    功能:从堆内存申请nmemb块,每块size字节大小的内存 返回值:成功返回申请到的连续内存的首地址,失败返回NULL
    注意:calloc申请到的内存会被初始化为0,速度比malloc慢 short *p = calloc(10,4) == malloc(40)
  4. void realloc(void *ptr,size_t size);
    功能:改变已有的堆内存的大小,size表示调整后的大小,在原有的基础上调大调小
    返回值:调整后内存块的首地址,一定要重新接受返回值,可能不是在原位置进行调整 如果无法在原位置调整:
    1.申请一块新的符合大小的内存
    2.拷贝原内存中的数据
    3.释放原内存,返回新内存首地址

四、malloc的内存管理机制

  1. 当首次向malloc申请内存,malloc会向操作系统申请内存,操作系统会直接分配33页(1页=4096字节)内存
    malloc管理,但是并不意味着可以越界访问,因为malloc可能把其它的内存分配给‘其他人’,这样就会产生脏数据
  2. 每个内存块之间会有空隙(4~12字节),一部分空隙是为了内存对齐,其中一定有4字节记录了malloc的维护信息,这些维护信息决定了下一次malloc分配内存的位置,如果破坏了维护信息,会影响下一次malloc或者free的过程

五、使用堆内存需要注意的问题

内存泄漏:
内存无法在使用,也无法被释放,需要再次使用时只能重新申请内存,然后继续重复以上过程,日积月累后可用的内存越来越少
注意:一旦进程结束,属于该进程的所有资源都会被操作系统回收
如何尽量的减少内存泄漏:谁申请谁释放,谁知道该释放谁释放
如何判断、定位内存泄漏
1、查看内存使用情况
win 任务管理器
Linux ps -aux命令
2、借助代码分析工具 mtrace 检查malloc和free是否成对出现
3、封装malloc、free,记录申请、释放的信息到日记文件中

void *m_malloc(size_t size)
{
	s = malloc(size);
	fprintf("h%d malloc",filename);
}
void m_free(void *ptr)
{
	free(ptr);
	
}

内存碎片:
已经释放了但无法继续使用的内存叫做内存碎片,它是由于申请和释放的时间不协调导致的,无法完全避免,只能尽量减少
如何减少内存碎片的产生:
1、尽量使用栈内存
2、不要频繁地申请、释放内存
3、尽量申请大块内存,自己来管理

六、内存清理函数

#include<stdio.h>
void bzero(void *s,size_t n);
功能:把一块内存清理为0
s;内存块的首字节
n:内存块的字节数

#include<string.h>
void *memset(void *s,int c,size_t n);
功能:把内存块按字节设置为c
s:内存块的首地址
c:想要设置ASCII值
n:内存块的字节数
返回值:成功设置后的内存首地址

七、堆内存定义二位数组

指针数组:
定义n行,m列二维数组
inr arr[10];
for(int i=0;i<n;i++)
{
arr[i] = malloc(m
sizeof(类型));
}
注意:每一行的m值可以不同,这种方式可以定义不规则的二维数组
优点:可以不规则、对内存要求较低
缺点:申请麻烦、容易产生内存碎片

数组指针
类型 (*arrp)[n] = malloc(sizeof(类型)nm);
申请m行n列的二维数组
缺点:对连续内存要求高,可能申请失败
优点:申请简单
注意:所谓的多维数组,其实都是用一维数组模拟

例子1:计算100~10000之间所有的素数,结果储存在堆内存中,尽量不要浪费内存

1、先计算有多少个、再一下全部申请出来

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<stdbool.h>
  4 bool math_is(int n);
  5 
  6 int main()
  7 {
  8     int *s = NULL;//置空
  9     int cnt = 0;
 10     for(int i=100;i<=10000;i++)
 11     {
 12         if(math_is(i))//调用函数,判断是否是素数
 13         {
 14             cnt++;
 15         }
 16     }
 17     s = malloc(4*cnt);
 18     int j = 0;
 19     for(int i=100;i<=10000;i++)
 20     {
 21 
 22         if(math_is(i))
 23         {
 24              s[j] = i;
 25              j++;
 26         }
 27     }
 28     for(int i=0;i<cnt;i++)
  29     {
 30         printf("%d ",s[i]);
 31     }
 32     return 0;
 33 }   
 34 
 35 bool math_is(int n)
 36 {
 37 
 38     for(int j=2;j<=n/2;j++)
 39     {
 40         if(n%j == 0)
 41         {
 42             return false;
 43         }
 44     }
 45     return true;
 46 
 47 }

2、一边算,一边申请

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>

bool is_prime(int num)
{
	for(int i=2;i<=num/2;i++)
	{
	if(0 == num%i)return false;
	}
}

int main()
{
	int *arr = NULL;
	for(int i=100;i<=10000;i++)
	{
		if(is_prime(i))
		{
			arr = realloc(arr,sizeof(int)*(cnt+1));
			arr[cnt++] = i;
		}
	}
}
for(int i=0;i<cnt;i++)
{
    printf("%d",arr[i]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值