现在的位置: 首页 > 综合 > 正文

请问内核的堆和栈的起始地址是在哪里设置的、有多大?(一个关于内核进程堆栈的讨论,不错)

2013年10月04日 ⁄ 综合 ⁄ 共 2993字 ⁄ 字号 评论关闭

 

 

JackieLau
(newbie)
07-02-07 10:14

请问内核的堆和栈的起始地址是在哪里设置的、有多大?

 

 

请问各位兄弟:

我看内核的链接脚本和System.map中,没有发现内核的栈的设置地址(而在像Bootloader中的链接脚本里面一般会指定栈的地址,在初始化的时候就把SP设置到这个地址)。
而在内核中没有发现在哪里设置的栈指针。

另外,我还想问,内核态的内存预留的堆和栈各有多大?在哪里设置的?

多谢各位!

--------------------
开心工作,快乐生活

文章选项:

coly
(addict)
07-02-07 15:20

Re: 请问内核的堆和栈的起始地址是在哪里设置的、有多大? [re: JackieLau]

 

 

我个人理解,不一定正确。而且我的理解经常错误,呵呵。

内核中的栈和堆与应用程序的栈和堆,概念上相同,但是在实现和使用上不太一样。

linux下应用程序的栈和堆都是基于虚拟内存的地址空间的概念的,就是对应内核中的vmalist。在应用程序中,栈和堆的起始地址是有约定的。

但是内核本身没有另外一个更高层的程序来管理内核的地址空间,所以内核空间的栈的组织,和应用程序有所不同。内核的栈如果溢出时,不能像应用程序那样产生一个page fault,然后分配新的地址空间,继续使用。内核的栈如果溢出,没有人知道,除非溢出的地方影响了运行,让程序crash

而内核本身更没有堆,堆在我理解是针对应用程序的,堆内的线性地址空间靠libc中的mallocfree来管理。堆的空间的扩大靠brk()系统调用。而内核的内存使用,get_free_pages来实现的(虽然上层封装了kmallocvmalloc),这个基本上是自己管理自己,由于Linux内核还不支持自己的swapping,所以内核如果找不到可用的页框了,也就没办法了。

最后,Linux下应用程序的堆起始地址,一般就是在bss后面开始。也许需要某个单位的地址对齐,也许中间还有一些堆的管理数据结构,但是大致就是这个位置。Linux下栈的起始,有两种方式:1,从3G往下某一个地址开始,往下生长,直到和堆碰上;2,在应用程序线性地址的低端,即文本段之前的低端地址空间的某一个位置开始,然后往下生长(这种情况下,栈的起始位置和文本段的起始位置中间会有一些空隙,主要是用来放置参数用的)。

而内核中,就比较随便了。首先内核中分配数据的可用页框区域,没有固定的起始地址。get_free_pages最初能获得哪个页框,完全取决于buddy系统的初始化算法,以及bootmem中内存分配的布局。这个和堆有点点不一样。
而内核的栈也很随便,完全可以get_free_pages获得一块连续的物理页框们,然后用它做内核栈——没有人会知道它是否溢出。除非在内核编译时加上栈溢出检查的配置,但是这样会频繁的检查是否栈溢出,速度慢得紧。

上面是我的主要的理解,可能具体的编码实现在linux中会有所差异。希望没有错误,呵呵。因为我理解有限,文字中的错误是经常和正常的。

--------------------
http://www.mlxos.org

文章选项:

JackieLau
(newbie)
07-02-07 16:14

Re: 请问内核的堆和栈的起始地址是在哪里设置的、有多大? [re: coly]

 

 

Coly,非常感谢你,多谢指点,也不必这么谦虚 :)
你写的东西对我很有帮助,多谢。

上面你说了,内核的栈起始是在BSS段的开始,那么结束位置呢?
我们知道BSS段是内存的低地址,内核线程的栈是否也是降栈呢?(从上面某个位置到BSS段),如果是降栈的话,那么最上面的地址是怎么确定的?(也就是我想问的预分配的栈是多大?)。
NOTE.
当然,如果使用增栈的话,就不会存在我问的问题了(栈从BSS段向上,到哪里是未知的)。

另外,我说的内核的堆就是用Kmalloc管理的那块内存,它的范围是多少呢?

请各位大侠们赐教。

--------------

我这个问题的引出是这样的,在单板上传给内核参数的内存大小是40Mmem=40M),然后在系统起来以后,看到的内存总大小却是36.7M,那剩下的内存去哪里了?

System.map中可以看出来,有3.16M是作为内存的代码段数据段BSS段,及初始化数据段等。
那么就是说剩下的就是内核的栈和堆了,它们是预先分配大小的话?如果是预先分配大小的那大小是多大?

还有另外一个问题,在System.map中可以看出,有一些初始化的代码与数据段,这些东西使用完后,会不会被重新利用起来呢?

上面算是我的问题的引论吧?

再次感谢Coly :)

--------------------
开心工作,快乐生活

文章选项:

JackieLau
(newbie)
07-02-07 16:34

Re: 请问内核的堆和栈的起始地址是在哪里设置的、有多大? [re: JackieLau]

 

 

补充:
上面所说的,看到的内存的总大小是指用cat /proc/meminfo中看出的。

--------------------
开心工作,快乐生活

文章选项:

coly
(addict)
07-02-07 16:38

Re: 请问内核的堆和栈的起始地址是在哪里设置的、有多大? [re: JackieLau]

 

 

1,“上面你说了,内核的栈起始是在BSS段的开始,那么结束位置呢?
我没有说过这样的话,从BSS段开始的,就是BSS。应用程序在BSS后面的某一个位置开始是他的堆区域。堆区域的起始地址和BSS的结尾中间很可能会有一个空隙,这段区域中很可能是堆的管理数据。
2
,我说过内核的栈的分配是比较随意的(我的理解),没有强制要求要在内核的某个地址空间位置上。确定栈的顶端很容易,譬如
ptr = (unsigned char *)get_free_pages(GFP_KERNEL, 0);
stack_base = ptr + PAGE_SIZE;
就这样就可以确定内核栈顶端了。我在写自己的mlxos的时候,就是这么做的。Linux 2.4idle线程似乎是一个预置的数组,但是思路都差不多。兄弟,别把你理解的我的话,说成是我说的话,在某些场合,我会被你害死的。
3
,另外再说一次,由于内核自己不会通过brk来扩展自己的地址空间(在内核初始化的时候,内核的地址空间都和物理内存映射好了),所以在内核中没有应用程序中的堆的概念。所以我认为我说的内核的堆就是用Kmalloc管理的那块内存,它的范围是多少呢?这个问题没有意义,因为内核的堆这个东西在我看来是一个不准确的概念。

关于最初问题的引出,我认为得看内核的内存初始化,以及显示数据的计算办法。我对嵌入式不熟悉,但是仅仅数字比数字是不行的。最好看看代码是如何根据你的40M得出36.7M的。

另外,兄弟我有一个建议,就是在做结论之前,最好能先验证一下自己的结论。不然这种风格真的会死人的,不是害死别人,就是把自己搞了。

希望我的语气没有严厉(我没有那个意思,只是看到你将自己的理解说成是我的话,后背有点凉)。其实我也是菜鸟,在论坛上跟大家互相请教的。一起进步,一起进步 :-)

--------------------
http://www.mlxos.org

文章选项:

leviathan
(addict)
07-02-07 16:46

Re: 请问内核的堆和栈的起始地址是在哪里设置的、有多大? [

【上篇】
【下篇】

抱歉!评论已关闭.