【问题标题】:Explanation for stack memory allocation function - C++栈内存分配函数说明-C++
【发布时间】:2021-03-16 07:46:09
【问题描述】:

我试图理解一个使用多线程和共享内存的程序。父线程调用如下函数,我不太明白它是如何工作的。

#define MAX_STACK_SIZE 16384  // 16KB  of stack

/*!
 * Writes to a 16 KB buffer on the stack. If we are using 4K pages for our
 * stack, this will make sure that we won't have a page fault when the stack
 * grows.  Also mlock's all pages associated with the current process, which
 * prevents the program from being swapped out.  If we do run out of
 * memory, the robot program will be killed by the OOM process killer (and
 * leaves a log) instead of just becoming unresponsive.
 */
void HardwareBridge::prefaultStack() {
  printf("[Init] Prefault stack...\n");
  volatile char stack[MAX_STACK_SIZE];
  memset(const_cast<char*>(stack), 0, MAX_STACK_SIZE);
  if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
    initError(
        "mlockall failed.  This is likely because you didn't run robot as "
        "root.\n",
        true);
  }
}
       
//Parent Thread
void HardwareBridge::run(){

  printf("[HardwareBridge] Init stack\n");
  prefaultStack();

  //printf("[HardwareBridge] Init scheduler\n");  // Commented because unrelated to current question
  //setupScheduler();
      
  // Calls multiple threads here
 
  for(;;){
  usleep(10000000);
  }
}

谁能解释一下这个函数的目的是什么。根据评论,我可以理解它可以防止堆栈大小超过 16KB。但是,共享内存主要是在程序中使用new 关键字动态分配的。动态内存分配不是发生在堆中而不是堆栈中吗?该函数在这种情况下有何帮助。

【问题讨论】:

  • 线程栈与共享内存完全无关。

标签: c++ memory-management shared-memory dynamic-memory-allocation


【解决方案1】:

根据评论,我可以理解它可以防止堆栈大小超过 16KB。

这不是注释所说的,也不是函数的作用。

谁能解释一下这个函数的目的是什么。

评论解释了它。该函数做了两件事:

  • 它预先分配了 16K 的堆栈。
  • 它“锁定”了分配的内存,防止它被交换到磁盘。

这两件事保证在堆栈使用量增长时不会出现页面错误(只要不超过 16K)。

但是,共享内存主要是动态分配的

没错。这意味着共享或其他动态内存分配与函数无关。

【讨论】:

    【解决方案2】:

    prefaultStack() 中,确保堆栈从之前的大小至少增加了 16K。然后通过调用mlockall() 将当前内存页锁定到内存,防止它们被换出。之后退出函数。

    我想说,这样做的唯一真正效果是确保无论如何,调用线程将至少有 16K 的可用堆栈,即使稍后某个饥饿的进程会耗尽所有剩余内存。

    【讨论】:

      【解决方案3】:

      根据我的理解,回复是内联的

      1. 根据评论,我可以理解它可以防止堆栈大小超过 16KB。

      不。 prefaultStack 函数在其堆栈上有char[MAX_STACK_SIZE],因此主进程的堆栈段大小为 4 页 +(主函数的堆栈大小)。并且此进程的任何虚拟内存页面(以及将来随着堆栈或堆增长而分配的任何虚拟内存页面)都不会被换出到交换区域,因为 mlockall 是用MCL_CURRENTMCL_FUTURE https://linux.die.net/man/2/mlockall 调用的。这是此功能的唯一功能。与动态内存、堆或共享内存无关。

      1. 但是,共享内存主要是在程序中使用 new 关键字动态分配的。

      您正在处理多线程,因此线程之间共享动态内存或堆地址空间。这段代码对两个进程之间的共享内存没有任何作用。

      1. 动态内存分配不是发生在堆中而不是堆栈中吗?该函数在这种情况下有何帮助。

      动态内存是从堆中分配的。而且这个功能不处理 以任何方式与堆。此代码仅确保进程的所有堆栈和堆页面(当前分配的和未来分配的)永远不会换出到交换区域,从而防止任何页面错误,这些页面错误是耗时且成本高昂的操作。

      【讨论】:

      • 您的格式有点混乱。您对自己的文本使用了引号格式,而对引号没有使用引号格式。
      • @largest_prime_is_463035818 更正了格式