【问题标题】:Too many calls to mprotect对 mprotect 的调用过多
【发布时间】:2010-10-25 05:59:32
【问题描述】:

我正在开发一个并行应用程序(C,pthread)。我跟踪了系统调用,因为在某些时候我的并行性能很差。我的跟踪显示我的程序多次调用mprotect()...足以显着减慢我的程序。

我确实分配了很多内存(使用malloc()),但只有合理数量的调用brk() 来增加堆大小。那么为什么会有这么多电话给mprotect() 呢?!

【问题讨论】:

  • 如果你有 strace 跟踪你的程序怎么样(Linux)。
  • 这正是我所做的。

标签: c multithreading parallel-processing system-calls


【解决方案1】:

您是否正在创建和销毁大量线程?

在分配线程堆栈时,大多数 pthread 实现都会添加一个“保护页”。这是一个访问受保护的内存页面,用于检测堆栈溢出。我希望每次创建或终止线程以(取消)保护保护页面时至少调用一次 mprotect 。如果是这种情况,有几个明显的策略:

  1. 在创建线程之前使用pthread_attr_setguardsize() 将保护页大小设置为零。
  2. 使用线程池(与处理器说的一样多的线程)。线程完成任务后,将其返回到池中以获取新任务,而不是终止并创建新线程。

另一种解释可能是,如果检测到溢出,您所在的平台将增加线程堆栈。我不认为这是在 Linux 上使用 GCC/Glibc 实现的,但最近有一些类似的提议。如果您在处理时使用大量堆栈空间,您可以使用pthread_attr_setstacksize 显式增加初始/最小堆栈大小。

或者它可能完全是别的东西!

【讨论】:

  • 不,我只在开始时创建了有限数量的线程,不过,谢谢。
  • 嗯...你在使用 mmap() 吗?我隐约记得我的一位同事遇到的一个问题,即 mprotect() 被多次调用 - 每页一次 - 一个映射区域。我不知道我们是否曾经深陷其中。是否可以发布 strace 输出?
  • @Wuggy 看起来好像已经过去了 10 年,但您还记得是否找到了根本原因吗?我使用 mmap() 遇到了同样的问题
【解决方案2】:

如果可以,请在调试 libc 下运行程序并在 mprotect() 上中断。查看调用堆栈,看看你的代码在做什么导致 mprotect() 调用。

【讨论】:

    【解决方案3】:

    具有 ptmalloc2 用于 malloc 的 glibc 库在内部使用 mprotect() 对主线程以外的线程的堆进行微管理(对于主线程,使用 sbrk()。) malloc() 首先使用 mmap 分配大块内存() 用于线程,如果堆区域似乎有争用,然后它会更改不必要部分的保护位以使其可以通过 mprotect() 访问。稍后,当它需要增加堆时,它会再次使用 mprotect() 将保护更改为读/写。这些 mprotect() 调用用于多线程应用程序中的堆增长和收缩。

    http://www.blackhat.com/presentations/bh-usa-07/Ferguson/Whitepaper/bh-usa-07-ferguson-WP.pdf 以更详细的方式解释这一点。

    【讨论】:

      【解决方案4】:

      “valgrind”套件有一个名为“callgrind”的工具,它会告诉你什么叫什么。如果您在“callgrind”下运行应用程序,则可以使用“kcachegrind”查看生成的配置文件数据(它可以分析由“cachegrind”或“callgrind”制作的配置文件)。然后只需双击左侧窗格中的“mprotect”,它就会显示调用它的代码以及调用次数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-29
        • 1970-01-01
        • 1970-01-01
        • 2015-10-26
        • 2012-03-05
        • 2020-12-05
        相关资源
        最近更新 更多