关于程序的bss段,堆区,栈区的一些学习。

 写汇编总结引发的思考,总结这东西还真是得多写。

 在学习汇编的时候,书上并没有区分堆栈的区别。并且没有说明bss和堆不是一个东西,搞得我以为堆和bss就是一个东西。

所以我就纳闷,malloc是从堆中分配空间,那么为什么分配后里面的值不是0?


于是查资料学到了很多东西,写篇博客存个档~我所说的全部是在linux下的。然后进一步的问题就来了,第一个问题:

堆和栈的区别有哪些呢?

1.堆是运行过程中系统分配的。但是栈是程序一执行就分配好了的。

2.堆的大小比栈的大小要大得多。

3.堆只能顺序使用。但是栈则是由程序员自己控制的。

4.堆分配的速度比栈的速度慢。

5.堆向高地址扩展,栈向低地址扩展。


而bss段是干嘛的呢?

一开始,因为在C里面大数组是不能存放在函数内的(栈空间较小),并且bss段并不保存在可执行文件中还可以分配大空间,所以我以为bss段就是堆。

而我发现真是情况就是:

在全局变量和静态变量虽然可能非常大,但是他们是存储在bss段中而不是堆的(初始化过的全局变量和静态变量在.data中定义)。

堆的作用基本只能是通过系统调用才能分配的。速度比bss段直接映射慢多了。

PS:现在的linux下gcc似乎已经不用bss显示声明了。我自己在linux下测试的时候全局数据就是一个.comm的定义,并没有见到bss。


还有为什么要区分初始化和未初始化的全局变量和静态变量呢?

我的想法是:

假设有一个静态区的大数组,那么在程序运行的时候很可能有一大部分并不会使用,并且存储的数据全为零。

那么在内核加载这个可执行文件的时候,内核就可以很方便的将其映射到一个内容全为0的分页当中去了。

所以少了很多的不必要的外存使用,也让分配内存变得简单。

但是初始化后的区域必须保存所初始化的变量。那么就不能简单的映射了,只有保存在.data中了。


网上的说法是:

在编程的时候,很可能动态定义了一个以后不用的全局或静态变量。那么在bss段映射的时候并不占用内存,只有用到的时候才真正分配内存。

大意就是这样,目的是为了防止程序员对内存使用上造成错误。


刚才又刚好有机会到隔壁的嵌入式老师那里蹭了下课,问了这个问题.

这种区分方式其实是为了避免程序员的错误而出现的 .

也就是说当你定义了一个全局指针.如果你没初始化并且还在.data段中.那么很可能就会产生严重的内存问题.

也就是所谓的野指针.这当然是很麻烦的,搞不好还会让程序崩溃.

所以为了防止这种情况发生,采取了不同的定义方式来解决这个问题.


其实还有一个位置也误导了我。那就是apue上面的进程地址空间图。


就像这个样。让我以为堆的空间是程序内部的,并且还是固定大小的,但是看汇编的时候又是从系统中分配的。所以到底哪个正确呢?

而且我们直到栈区大小是固定的(有上限,并且支持虚拟存储),我个人猜测是将一部分链接到进程中(图中的位置),另一部分存在外存。

又或者是类似于链表一样可扩充空间的数据结构。

我之前有篇文章做过测试。不断的malloc分配空间,并且不断的将数据写入空间,实际情况刚好可以覆盖到linux的2Gswap空间。

http://blog.csdn.net/meiboyu/article/details/12885171

这也就是说linux下,堆的空间也是支持虚拟存储的(应该用到内存的地方都会支持。。)。


嗯,又请教了老师.

老师说其实对于32位系统上来说,所有程序虚拟内存都是4G的.所以,对于除了正文段和两个数据段还有一些参数段.栈和堆占据了其余的部分.

并且他指出栈段是动态的,我也说明栈是有上限的..我个人认为他指的动态应该是栈的变化.然后说堆是固定大小的.

因为除开这些其余都是可使用的地址空间.注意是地址空间.所以对于一个32位机上的程序,其堆的大小也是有上限的.

其实这个又和我之前的一篇关于地址和内存的关系的文章对应上了.


PS:刚和别人讨论到堆和栈对于多线程的数据结构,我记得在哪里看到过,linux线程就基本是进程。

所以我估计对于linux的堆和栈来说,可能每个线程都存在一个这样的数据结构。

记得i3的CPU是双核四线程。可能在CPU级别上提供了多个栈寄存器用来指向不同栈帧吧。


PSS:没错..又是和老师讨论后的观点.老师说对于多线程来说,系统的调度的最小单位是基于线程的.

说到这里应该明白了吧..意思就是线程之间代码是分开的.堆栈也是分开的.所以也就不存在内存的栈帧浮动的问题了.


看来自己目前学的还是太浅了.对于这么多知识完全没有联系起课堂上的理论来啊...

看内核是一方面,另一方面还是要多加加强理论与实际的联系啊!!

----------------------------------------几个月后的分割线-----------------------------------------------------------------------------------

Linux中,线程是共享代码区的.只是单独分配栈和一些必要的管理信息.并且对于进程,在没有代码区改变时,对于数据改变也是如此.只有在子进程改变了数据Linux才会分配新的.data页面.

上面的我就不改了..毕竟也是哥的一段青葱岁月...

感觉培训老师还没我晓得的多.....再一次感觉培训是个坑......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值