Gee*_*eek 4 process java process-management multithreading
从Unix 环境中的高级编程一书中,我阅读了以下关于类 Unix 系统中的线程的行
一个进程内的所有线程共享相同的地址空间、文件描述符、堆栈和进程相关属性。由于它们可以访问相同的内存,因此线程之间需要同步访问共享数据以避免不一致。
作者stacks在这里是什么意思?我做 Java 编程并且知道每个线程都有自己的堆栈。所以我对这里的共享 stacks概念感到困惑。
在 Unix 或 linux 进程的上下文中,短语“堆栈”可能意味着两件事。
首先,“堆栈”可以表示控制流的调用序列的后进先出记录。当一个进程执行时,main()首先被调用。main()可能会打电话printf()。编译器生成的代码将格式字符串的地址和任何其他参数printf()写入某些内存位置。然后代码写入printf()完成后控制流应返回的地址。然后代码调用跳转或分支到printf(). 每个线程都有这些函数激活记录堆栈之一。请注意,许多 CPU 都有用于设置和维护堆栈的硬件指令,但其他 CPU(IBM 360 或其他任何名称)实际上使用了可能分散在地址空间中的链表。
其次,“堆栈”可以表示 CPU 将参数写入函数的内存位置,以及被调用函数应返回的地址。“堆栈”是指进程地址空间的一块连续部分。
Unix 或 Linux 或 *BSD 进程中的内存是一条很长的行,从大约 0x400000 开始,到大约 0x7ffffffffffff(在 x86_64 CPU 上)结束。堆栈地址空间从最大的数字地址开始。每次调用函数时,函数激活记录的堆栈“向下增长”:进程代码将函数参数和返回地址放在激活记录的堆栈上,并递减堆栈指针,这是一个特殊的 CPU 寄存器,用于跟踪在堆栈的地址空间中,进程当前变量的值所在的位置。
每个线程获得一块“堆栈”(堆栈地址空间)供自己用作函数激活记录堆栈。在 0x7ffffffffffff 和较低地址之间的某个地方,每个线程都有一个保留用于函数调用的内存区域。通常这只是通过约定而不是硬件强制执行,因此如果您的线程在嵌套函数之后调用函数,则该线程的堆栈底部可以覆盖另一个线程堆栈的顶部。
所以每个线程都有一块“堆栈”内存区域,这就是“共享堆栈”术语的来源。这是进程地址空间是单个线性内存块以及术语“堆栈”的两种用法的结果。我很确定一些较旧的 JVM(非常古老)实际上只有一个线程。Java 代码中的任何线程实际上都是由单个真实线程完成的。较新的 JVM,即调用真实线程来执行 Java 线程的 JVM,将具有我上面描述的相同“共享堆栈”。Linux 和 Plan 9 有一个进程启动系统调用(Linux 的 clone(),Plan 9 中的 rfork()),它可以设置共享部分地址空间的进程,也许不同的堆栈地址空间,但这种风格的线程从未真正流行起来。
| 归档时间: |
|
| 查看次数: |
1612 次 |
| 最近记录: |