专题五-内存管理的艺术
来源:互联网 发布:中越中美网络大战 编辑:程序博客网 时间:2024/06/05 06:55
动态内存分配
为什么使用动态内存分配?
(1)C语言中的一切操作都是基于内存的
(2)变量和数组都是内存的别名,如何分配这些内存由编译器在编译期间决定
.定义数组的时候必须制定数组的长度
.而数组长度在编译期就必须决定的
需求:程序运行的过程中,可能需要使用一些额外的内存空间
malloc和free
(1)malloc所分配的是一块连续的内存,以字节为单位,并且不带任何的类型消息
(2)free用于将动态内存归还于系统:void* malloc( size_t,size);void free(void* pointer)
注意:(1)malloc实际分配的内存可能会比请求的稍微多一点,但是不能依赖于编译器的这个行为
(2)当请求的动态内存无法满足时malloc返回NULL
(3)当free的参数为NULL时,函数直接返回
calloc和realloc
(1)你认识malloc的兄弟吗? void* calloc(size_t size,size_t num),num为类型的大小,size为元素的数目
(2)calloc的参数代表所返回内存的类型信息
(3)calloc会将返回的内存初始化为0;malloc分配的值时随机的!!!!!
void* realloc(void* pointer,size_t new_size)
(4)realloc用于修改一个原先已经分配的内存块大小,新分配的值也随机!!!!!
在使用realloc之后应该使用其返回值
当pointer的第一个参数为NULL时,等价于malloc
实例分析:calloc和realloc的使用
小结:
(1)动态内存分配是C语言中的强大功能
(2)程序能够在需要的时候有机会使用更多的内存
(3)malloc单纯的从系统的中申请固定字节大小的内存
(4)calloc能以类型大小为单位申请内存并初始化为0
(5)realloc用于重置内存大小
问题:malloc(0)将返回什么?
程序中的三国天下
程序中的栈
(1)栈是现代计算机程序里最为重要的概念之一
(2)栈在程序中用于维护函数调用上下文,没有栈就没有函数,没有局部变量
(3)栈保存了一个函数调用所需的维护信息
.函数参数,函数返回地址
.局部变量
.函数调用上下文
程序中的堆
(1)为什么有了栈还需要堆?栈上的数据在函数返回之后就会释放掉,无法传递到函数外部,如:局部数组
(2)堆是程序中一块巨大的内存空间,可由程序自由使用
(3)堆中被程序申请使用的内存在程序主动释放前将一直有效
malloc从堆中申请内存。对空间专门为了动态内存分配而产生的。
堆空间通过申请才能获得
(4)系统对堆空间的管理方式
.空间链表法,位图法,对象池法等等
4与5相近
表头之后指向12个字节,p就指向了5个字节,前面说的 申请的时候内存会多一点就是这个意思
free就是插入节点
如果只使用不归还,只malloc不free会导致什么后果?导致这个链表中所有的空闲节点全部被用完,空闲链表的表头就会指向NULL
程序中的静态存储区
(1)程序静态存储区随着程序的运行而分配空间,直到程序运行结束
(2)在程序的编译期静态存储区的大小就已经确定
(3)程序的静态存储区主要用于保存程序中的全局变量和静态变量
(4)与栈和堆不同,静态存储区的信息最终会保存到可执行程序中
小结
(1)栈,堆和静态存储区是C语言程序常涉及的三个基本存储区
(2)栈区主要用于函数调用的使用
(3)堆区主要用于内存的动态申请和归还
(4)静态存储区用于保存全局变量和静态变量
程序的内存布局
程序文件的一般布局
文件布局在内存中的映射
为什么在前面找不到栈和堆?因为栈和堆是要等到程勋运行之后操作系统分配他们的空间的
各个段的作用
(1)堆栈段在程序运行之后才正式存在,是程序运行的基础
(2).bss段存放的是未初始化的全局变量和静态变量的,全都为0
(3).text存放的是程序中的可执行代码
(4).data段存放的是那些已经初始化了的 全局变量和静态变量
(5).rodata段存程序中的常量值,如字符常量
这样的字符串肯定不会再栈上分配空间,因为我们main函数建立的活动记录里面只可能有指针变量p的空间,不会有helloworld的空间,他放在一个段里面rodata。
运行结果
段错误。
注释 *(p+1)='q';
运行结果
hqllo world1
hello world2
原因:
一、a与p类型不同:p为指向字符串的指针;a为保存字符串的数组。
5 char a[] = "hello world1"; 是个赋初值的字符数组。
6 char *p = "hello world2"; 是个字符串常量指针;
指针变量p在栈里面
字符串常量"hello world2"在全局数据区,数据段,只读,不可写
二、"hello world2"和"hello world1"字符串保存的位置不同。"hello world1"保存在栈
中,可用*(a+1)='q'修改,"hello world2"保存在全局数据
区,位置是在.rodata中,不能修改*(p+1)='q'
程序术语对应关系
(1)静态存储区通常指程序中的.bss和.data段
(2)只读区通常指程序中的.rodata段
(3)局部变量所占空间为栈上空间
(4)动态空间为堆中空间
(5)程序的可执行代码存放于.text段
问题: 函数的地址对应程序的哪一个段?应该是我们进程空间里面程序的内存空间里面存放代码段的某个地址。
同是全局变量和静态变量,为什么初始化和未初始化的保存在不同段中呢??????
C规定,未初始化变量的初值为0,这个清0的操作是由启动代码完成的,还有已初始化变量的初值的设置,也是由启动代码完成的。
为了启动代码的简单化,编译链接器会把已初始化的变量放在同一个段:.data,这个段的映像(包含了各个变量的初值)保存在“只读数据段”,这样启动代码就可以简单地复制这个映像到 .data 段,所有的已初始化变量就都初始化了。
而未初始化变量也放在同一个段:.bss,启动代码简单地调用 memset 就可以把所有未初始化变量都清0。
头疼的野指针
初始野指针
(1)野指针通常是因为指针变量中保存的值不是一个合法的内存地址而造成的
(2)野指针不是NULL指针,是指向不可用内存的指针
(3)NULL指针不容易用错,因为NULL语句和好判断一个指针是不是NULL
C语言没有任何手段可以判断一个指针是否是野指针
野指针的由来
(1)局部指针变量没有被初始化
(2)使用已经释放过后的指针
(3)指针所指向的变量在指针之前被销毁
经典错误,你犯了吗?
非法内存操作分析
(1)结构体成员指针未初始化
(2)没有为结构体指针分配足够的内存
d1中的p是野指针,p没有分配动态内存空间,p指向的是随机的
d2中的p是分配呢5个int,但是分配10个,这种bug很难查
内存初始化分析
(1)内存分配成功,但未被初始化
内存越界分析
(1)数组越界
内存泄漏分析
设计程序最好要单入口单出口
多次释放指针
谁申请谁释放
使用已经释放的指针
交通规则,还是应该遵守
C语言中的交通规则
(1)用malloc申请了内存之后,应该立即检查指针值是否为NULL,防止使用值为NULL的指针
(2)牢记数组长度,防止数组越界操作,考虑使用柔性数组
(3)动态申请操作必须和释放操作匹配,防止内存泄漏和多次释放
(4)free指针之后必须立即赋值为NULL
0 0
- 专题五-内存管理的艺术
- 内存管理的艺术
- 主题五 内存管理的艺术----29.动态内存的分配
- 主题五 内存管理的艺术----30.内存中的三雄并立
- 主题五 内存管理的艺术----31.程序文件的一般布局
- 主题五 内存管理的艺术----32.头疼的野指针
- C语言内存管理的艺术
- 【专题】详细介绍Java的内存管理与内存泄露
- c语言要点摘录(29~32 内存管理的艺术)
- C语言深度解剖读书笔记(5.内存管理的艺术)
- C语言深度解剖读书笔记(5.内存管理的艺术)
- C语言深度解剖读书笔记(5.内存管理的艺术)
- C语言学习记录(六):内存管理的艺术
- C语言深度剖析-----内存管理的艺术
- 内存的管理艺术(基于C语言)1
- 内存的管理艺术(基于C语言)2
- 项目管理的艺术
- 管理的诱导艺术
- ModelAndView传递参数到JSP页面
- 写一个SVG图形
- spring定时任务.线程池,自定义多线程配置
- Access2016学习8
- Swift_Base_01
- 专题五-内存管理的艺术
- APP安全测评
- html 盒子模型基础(display ,overflow,默认样式)(四)
- 分布式锁的几种实现方式
- html5学习笔记(四)(摘抄讲义加部分理解)
- 图像卷积运算
- hadoop3重要新特性——擦除编码解释
- iOS App组件化开发实践
- 关于C语言函数返回值问题