Linux上的clone()系统调用接受一个指向堆栈的参数,以供新创建的线程使用.显而易见的方法是简单地malloc一些空间并传递它,但是你必须确保你已经使用了大量的堆栈空间,因为该线程将使用(很难预测).
我记得在使用pthreads时我不必这样做,所以我很好奇它做了什么.我遇到了这个网站,它解释说,"Linux pthreads实现使用的最佳解决方案是使用mmap来分配内存,标志指定在使用时分配的内存区域.这样,内存分配给根据需要使用堆栈,如果系统无法分配额外的内存,则会发生分段违规."
我曾经听过mmap使用的唯一上下文是将文件映射到内存,实际上读取mmap手册页需要一个文件描述符.如何使用它来分配一堆动态长度来给clone()?这个网站真的很疯狂吗?;)
在任何一种情况下,内核都不需要知道如何为新堆栈找到一堆免费内存,因为在用户启动新进程时,它必须始终做什么?如果内核已经能够解决这个问题,为什么首先需要首先指定堆栈指针?
ulimit -s <value>和Linux实现中的堆栈大小(在线程级别)之间的关系是什么(或者对于任何操作系统而言)?
是<number of threads>*<each thread stack size>必须小于< stack size assigned by ulimit command>正当理由?
在下面的程序中 - 每个线程分配char [PTHREAD_STACK_MIN]并创建10个线程.但是当ulimit设置为10*PTHREAD_STACK_MIN时,它不会因中止而进行coredump.对于stacksize的一些随机值(远小于10*PTHREAD_STACK_MIN),它进行核心转储.为什么这样?
我的理解是stacksize表示进程总和中所有线程占用的堆栈.
线程功能
#include <cstdio>
#include <error.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/resource.h>
using namespace std;
#include <pthread.h>
#include <bits/local_lim.h>
const unsigned int nrOfThreads = 10;
pthread_t ntid[nrOfThreads];
void* thr_fn(void* argv)
{
size_t _stackSz;
pthread_attr_t _attr;
int err;
err = pthread_attr_getstacksize(&_attr,&_stackSz);
if( 0 != err)
{
perror("pthread_getstacksize");
}
printf("Stack size - %lu, Thread …Run Code Online (Sandbox Code Playgroud) 尝试测试时是否允许访问跨越x86中零边界的内存?在Linux的用户空间中,我编写了一个32位测试程序,该程序试图映射32位虚拟地址空间的低和高页。
之后echo 0 | sudo tee /proc/sys/vm/mmap_min_addr,我可以映射零页面,但是我不知道为什么不能映射-4096(即(void*)0xfffff000最高页面)。 为什么要mmap2((void*)-4096)退货-ENOMEM?
strace ./a.out
execve("./a.out", ["./a.out"], 0x7ffe08827c10 /* 65 vars */) = 0
strace: [ Process PID=1407 runs in 32 bit mode. ]
....
mmap2(0xfffff000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0
Run Code Online (Sandbox Code Playgroud)
另外,什么支票在中拒绝它linux/mm/mmap.c,为什么要这样设计?这是确保创建指向一个过去的对象的指针不会回绕并中断指针比较的部分吗,因为ISO C和C ++允许创建指向过去的一个指针,但不能在外部对象。
我在64位内核(Arch Linux上为4.12.8-2-ARCH)下运行,因此32位用户空间具有整个可用的4GiB。(与64位内核或32位内核(其中2:2或3:1用户/内核拆分会使高页成为内核地址)上的64位代码不同。)
我没有尝试使用最小的静态可执行文件(没有CRT启动程序或libc,只有asm),因为我认为这不会有所作为。没有一个CRT启动系统调用看起来可疑。
在断点处停下来时,我检查了一下/proc/PID/maps。主页尚未使用。堆栈包括第二高的页面,但未映射首页。
00000000-00001000 rw-p 00000000 …Run Code Online (Sandbox Code Playgroud) 我们知道每个线程都有自己的堆栈。这些堆栈分配在哪里?我读了一些文档,似乎堆栈是在创建线程时从堆中分配的。这有道理吗?提前致谢!
我浏览了一段时间,试图例如在执行操作时了解如何将内存分配给堆栈:
push rax
Run Code Online (Sandbox Code Playgroud)
或者移动堆栈指针为子例程的局部变量分配空间:
sub rsp, X ;Move stack pointer down by X bytes
Run Code Online (Sandbox Code Playgroud)
据我了解,堆栈段在虚拟内存空间中是匿名的,即不是文件支持的。
我还了解的是,内核不会真正将匿名虚拟内存段映射到物理内存,直到程序对该内存段进行实际操作(即写入数据)为止。因此,尝试在写入该段之前先读取该段可能会导致错误。
在第一个示例中,如果需要,内核将在物理内存中分配一个帧页。在第二个示例中,我假设内核不会在程序实际将数据写入堆栈堆栈段中的地址之前将任何物理内存分配给堆栈段。
我在正确的轨道上吗?