我正在开发并行应用程序(C,pthread)。我跟踪系统调用,因为在某些时候我的并行性能很差。我的跟踪显示我的程序多次调用mprotect()
......足以显着减慢我的程序。
我确实分配了大量内存(使用malloc()
),但只有合理数量的调用brk()
才能增加堆大小。那么为什么这么多人打电话给mprotect()
?
答案 0 :(得分:3)
您是在创建和销毁大量线程吗?
大多数pthread实现将在分配线程堆栈时添加“保护页面”。它是一个访问受保护的内存页面,用于检测堆栈溢出。每次创建或终止线程时,我都希望至少有一次调用mprotect来(保护)保护页面。如果是这种情况,有几个明显的策略:
pthread_attr_setguardsize()
将防护页面大小设置为零。另一种解释可能是你在一个平台上,如果检测到溢出,就会增加线程的堆栈。我不认为这是在具有GCC / Glibc的Linux上实现的,但最近有这些方面提出了一些建议。如果在处理过程中使用大量堆栈空间,则可以使用pthread_attr_setstacksize
显式增加初始/最小堆栈大小。
或者它可能完全是另一回事!
答案 1 :(得分:2)
如果可以的话,在调试libc下运行程序并在mprotect()上中断。查看调用堆栈,看看你的代码正在做什么导致mprotect()调用。
答案 2 :(得分:2)
为其malloc使用ptmalloc2的glibc库在内部使用mprotect()对主线程以外的线程进行堆的微管理(对于主线程,使用sbrk()代替。)malloc()首先使用mmap分配大块内存()如果一个堆区域似乎有争用,那么它将更改不必要部分的保护位,以使其可以通过mprotect()访问。之后,当需要增加堆时,它会再次使用mprotect()将保护更改为可读/可写。那些mprotect()调用用于多线程应用程序中的堆增长和收缩。
http://www.blackhat.com/presentations/bh-usa-07/Ferguson/Whitepaper/bh-usa-07-ferguson-WP.pdf 用更详细的方式解释了这一点。
答案 3 :(得分:0)
'valgrind'套件有一个名为'callgrind'的工具,可以告诉你什么叫什么。如果您在'callgrind'下运行应用程序,则可以使用'kcachegrind'查看生成的配置文件数据(它可以分析'cachegrind'或'callgrind'创建的配置文件)。然后双击左侧窗格中的“mprotect”,它将显示调用它的代码和次数。