11.内存分配

brk()和sbrk()

#include <unistd.h>
int brk(void *end_data_segment);
	Returns 0 on success, or -1 on error.
void *sbrk(intptr_t increment);
	Returns previous program break on success, or (void*)-1 on error

这两个函数,目前的水平是没必要用,看看就行了。

  • brk()设定program break(堆的顶部)为end_data_segment所指的位置,由于虚拟内存以页为单位进行分配,end_date_segment实际会四舍五入到下一个内存页的边界处。设定为低于&end的位置,会有无法预知的行为。
  • sbrk()在原有地址上增加从参数increment传入的大小(在linux中,sbrk()实现是基于 brk()的),调用成功会返回前一个program_break的地址。(对此有用法sbrk(0)以监视内存分配函数包的行为)

malloc()、calloc()、realloc()、free()

这三个都是C语言的基础,就不啰嗦了。
其中realloc()新分配的内存是未初始化的
传给free()空指针,什么都不会做,但是如果两次释放同一个指针以及对释放过的指针的任何使用,都会产生错误,可能导致不可预知的后果。(free()两次空指针似乎不会报错,毕竟free(NULL)什么都不会做)

#include <stdlib.h>
void *malloc(size_t size);
	Returns pointer to allocated memory on success, or NULL on error
void *calloc(size_t numites, size_t size);
	Returns pointer to allocated memory on success, or NULL on error
void *realloc(void* ptr, size_t size);
	Returns pointer to allocated memory on success, or NULL on error
void free(void* ptr);

memalign()和posix_memalign()

这两个函数的作用是分配内存时,起始地址可以与2的整数次幂对齐。对于某些应用非常有用。(水平不够,用不上)

#include <malloc.h>
void *memalign(size_t boundary, size_t size);
	Returns pointer to allocated memory on success, or NULL on error

memalign()分配size个字节,起始地址是boundry的整数倍,而boundry必须是2的整数次幂。(这个函数并非所有UNIX系统都实现了。大多数提供memalign()的其他UNIX实现都要求引用头文件<stdlib.h>而非<malloc.h>以获得函数声明)。

#include <stdlib.h>
int posix_memalign(void **memptr, size_t alignment, size_t size);
	Returns 0 on success, or a positive error number on error

这个是SUSv3规范里的函数,不过似乎还没有完全普及。
已经分配的内存地址会通过参数memptr返回;内存与alignment的整数倍对齐,alignment必须是sizeof(void*)(在大多数硬件架构上是4或8个字节)与2的整数次幂两者间的乘积。
出错时不会返回-1,而是返回错误号(即通常在errno中返回的正整数)。

示例

例如,如果 sizeof(void*)是4,就可以使用posix_memalign()分配65536字节的内存,并与4096字节的边界对齐:

int s;
void *memptr;
s = posix_memalign(&memptr, 1024 * sizeof(void*), 65536);
if(s != 0)
	/*Handle error*/

alloca()

感觉这是最有用的一个~

#include <alloca.h>
void *alloca(size_t size);
	Returns pointer to allocated block memory

作用

参数size指定在堆栈上分配的字节数。会返回分配内存块的指针。不需要也不可能调用free()来释放alloca()分配的内存。 同样也不能用realloc()来调整alloca()分配的内存大小。

可移植性

虽然这个函数不是SUSv3规范中的,但大多数UNIX都提供了此函数。所以也具有可移植性
旧版本的libc 和其他一些UNIX实现(主要是BSD的衍生版本),要获取alloca()函数的声明,需要引入<stdlib.h>而非<alloca.h>

特点

  • 若调用alloca()造成堆栈溢出,则程序行为无法预知,特别是没有收到NULL返回值时。(事实上,可能会收到一个SIGSEGV信号)。
  • 不能在一个函数参数列表中调用alloca()
    如:
func(x, alloca(size), z)

这会使alloca()分配的堆栈空间出现在当前参数的空间内(函数参数都位于栈帧内的固定位置)。相反,必须采用这样的代码:

void *y;
y = alloca(size);
func(x, y, z);
  • 在信号处理程序中调用longjmp()setjmp(),以执行非局部条扎un时,alloca()的作用尤其突出。此时,在“起跳”函数和“落地”函数之间的函数中,如果调用了malloc()来分配内存,要想避免内存泄露极其困难,甚至是不可能的。但是,调用alloca()就完全可以避免这一问题,因为堆栈时由这些调用展开的,所以已分配的内存会被自动释放。
    (这个特性真的很妙,不懂的应该是longjmp()setjmp()的实现原理没搞清楚。可以看看我的上一篇博客 setjmp()与longjmp()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1 内存的编址方式是通过地址编码来描述内存位置的一种方式。 2. CPU 寻址是指 CPU 在内存中搜索指定地址的过程。 3. 程序的逻辑地址是指程序中变量或参数的地址,它是指程序的相对位置而不是绝对位置。 4. 程序的线性地址是指程序在内存中的实际位置,它是绝对地址。 5. 程序的物理地址是指程序在物理内存中的位置,它是绝对地址。 6. 程序的地址重定位是指将程序的逻辑地址转换为物理地址的过程。 7. 程序的链接是指将各个模块组合在一起,以形成一个完整程序的过程。 8. 存储器管理程序的功能包括内存分配、收回和保护。 9. 定长的连续内存分配是指把程序分成相同大小的内存块,然后连续分配给程序的过程。 10. 不定长的连续内存分配是指把程序按实际需要分配不同大小的内存块,然后连续分配给程序的过程,常用的算法有最佳适配算法和最先适配算法。 11. 分段式内存分配是把程序分成若干段,根据段的长度和大小来分配内存的过程。 12. 分页式内存分配是把程序分成若干页,根据页的大小来分配内存的过程。1) 分层页表的工作原理是通过多级页表来提高内存的寻址速度,优点是提高了内存的寻址速度,缺点是需要更多的内存空间来存储页表。2) 哈希页表的工作原理是建立哈希表来存储页面的位置,优点是减少了内存的查找时间,缺点是建立哈希表非常耗时。3) 倒置页表的工作原理是建立一个倒置表,即物理地址对应逻辑地址,优点是可以提高内存寻址的速度,缺点是缺乏灵活性。 13. 段页式内存分配是把程序以段和页的形式分配内存,以便更好地使用内存空间。 14. TLB(快表)是一个特殊的硬件,它可以加快程序的内存寻址速度,它可以存储页表中的常用项,以便快速查找。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

barbyQAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值