C++ Q&A(三) C++的内存模型

来源:互联网 发布:java合并两个单链表 编辑:程序博客网 时间:2024/06/06 21:41

声明:Q&A系列的文章是我在平时自己遇到的或者看到的一些问题,本着再小的问题也需要有人解答的想法,将这些问题和答案整理出来。

欢迎和我讨论问题,同时也欢迎转载Q&A系列的文章。



先介绍一下内存的分段机制:

在虚拟内存中,一个程序为了方便共享和保护,就会使用分段。分段是把一个程序分成独立的地址空间,每个段都有自己的基址和长度,在纯分段系统给中,段内地址是一段连续的内存,在段页式系统中,段内地址也分成页号和页内地址,允许离散的分配空间。


gcc在编译程序的时候,把程序分成了很多个段,下面是几个比较经典的段:


上面这个图是从上到下,代表的是从高地址到低地址。


.env段:存放这环境变量和gcc赋予程序的一些变量。

.stack:很明显这个就是栈啦,栈里面存放着局部变量。

shared memory段:这个段存放着要使用的动态链接库的函数,比如很常见的printf.o 和  malloc.o

.bss段:这里存放的是没有被初始化的静态变量,这个段会在程序开始运行的时候被初始化为0.

.data段:这里存放这已经被初始化的静态变量。

.text:这个段也叫正文段,里面存放着程序的正文,你的exe文件的二进制指令。这段是只读的,这个程序的所有进程共享这个正文段。

.rodata:这个段也叫常量区,常量区里面存放着没有名字的常量,最常见的就是字符串常量,


关于stack和heap:

1.stack和heap的生长和大小

stack是从高地址向低地址生长的,heap是从低地址向高地址生长的。线程中的栈的大小一般是8M,而进程的栈大小一般是比线程栈大,但是不会超过线程栈的两倍。在linux下使用 命令 

ulimit -s
可以查看一个线程栈的默认大小。

而一个进程中的堆的大小是一般是可以很大的,可以达到虚拟内存大小。


2.一个进程可以用多少个线程栈?

    线程栈的大小是8M,假设你的内存是4G,而系统占用你的高地址的3G~4G部分,只能下3G左右的大小,3G除以8M = 384,而系统中一般不止一个进程,因此实际能创建能创建的线程要比这个数要小。

3.它们的生存范围
    栈是依附在线程上的,因此当一个线程退出的时候,这个栈的空间就会被回收。堆是在一个进程运行期间被分配,当这个进程结束的时候,所有分配给他的堆空间都会被回收。

4.它们的大小取决于什么?
    栈的大小取决与在线程创建的时候指定的属性,在linux中线程属性类的是pthread_attr_t。通过pthread_attr_init函数来初始化这个类型,然后就可以使用这个属性去指定线程的属性。通过pthread_create创建线程。如果想要知道一个线程的栈的大小的话,可以使用pthread_getstacksize()来获取,然后通过pthread_setstacksize。

5.堆和栈谁的速度比较快?
    栈比堆的速度比较快。因为栈的访问模式使得栈的空间很容易的被释放和分配(只是简单的指针的加减)。但是堆的分配就要复杂的多。而且,当栈中的某一个字节被频繁的使用时,这个字节会被映射进处理器的cache中,让它更快的被访问。而另一个影响堆的性能的是,堆是一个全局资源,访问这个全局资源往往会涉及到多线程安全问题和同步等问题。



1 0
原创粉丝点击