【问题标题】:Why does my process take too long to die?为什么我的过程需要很长时间才能死掉?
【发布时间】:2015-09-17 04:49:02
【问题描述】:

基本上我在 PowerPC (Freescale e500mc) 上使用 Linux 2.6.34。我有一个使用大约 2.25 G 的 mlocked VM 的进程(一种内部开发的 VM)。当我杀死它时,我注意到它需要超过 2 分钟才能终止。

我调查了一下。首先,我关闭了所有打开的文件描述符,但这似乎没有什么不同。然后我在内核中添加了一些 printk,通过它我发现所有延迟都来自内核解锁我的 VMA。页面之间的延迟是一致的,我通过反复检查 /proc/meminfo 中的锁定页面计数来验证这一点。我检查了分配那么多内存的程序,一旦我发出信号,它们就会全部死掉。

你认为我现在应该检查什么?感谢您的回复。

编辑:我必须找到一种方法来分享有关该问题的更多信息,因此我编写了以下程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>

#define MAP_PERM_1              (PROT_WRITE | PROT_READ | PROT_EXEC)
#define MAP_PERM_2              (PROT_WRITE | PROT_READ)

#define MAP_FLAGS               (MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE)

#define PG_LEN                  4096
#define align_pg_32(addr)       (addr & 0xFFFFF000)
#define num_pg_in_range(start, end)     ((end - start + 1) >> 12)

inline void __force_pgtbl_alloc(unsigned int start)
{
        volatile int *s = (int *) start;
        *s = *s;
}

int __map_a_page_at(unsigned int start, int whichperm)
{
        int perm = whichperm ? MAP_PERM_1 : MAP_PERM_2;

        if(MAP_FAILED == mmap((void *)start, PG_LEN, perm, MAP_FLAGS, 0, 0)){
                fprintf(stderr,
                        "mmap failed at 0x%x: %s.\n",
                        start, strerror(errno));
                return 0;
        }

        return 1;
}

int __mlock_page(unsigned int addr)
{
        if (mlock((void *)addr, (size_t)PG_LEN) < 0){
                fprintf(stderr,
                        "mlock failed on page: 0x%x: %s.\n",
                        addr, strerror(errno));
                return 0;
        }

        return 1;
}

void sigint_handler(int p)
{
        struct timeval start = {0 ,0}, end = {0, 0}, diff = {0, 0};
        gettimeofday(&start, NULL);
        munlockall();
        gettimeofday(&end, NULL);
        timersub(&end, &start, &diff);

        printf("Munlock'd entire VM in %u secs %u usecs.\n",
                diff.tv_sec, diff.tv_usec);

        exit(0);
}

int make_vma_map(unsigned int start, unsigned int end)
{
        int num_pg = num_pg_in_range(start, end);

        if (end < start){
                fprintf(stderr,
                        "Bad range: start: 0x%x end: 0x%x.\n",
                        start, end);
                return 0;
        }

        for (; num_pg; num_pg --, start += PG_LEN){
                if (__map_a_page_at(start, num_pg % 2) && __mlock_page(start))
                        __force_pgtbl_alloc(start);
                else
                        return 0;
        }

        return 1;
}

void display_banner()
{
        printf("-----------------------------------------\n");
        printf("Virtual memory allocator. Ctrl+C to exit.\n");
        printf("-----------------------------------------\n");
}

int main()
{
        unsigned int vma_start, vma_end, input = 0;
        int start_end = 0; // 0: start; 1: end;

        display_banner();

        // Bind SIGINT handler.
        signal(SIGINT, sigint_handler);

        while (1){
                if (!start_end)
                        printf("start:\t");
                else
                        printf("end:\t");

                scanf("%i", &input);

                if (start_end){
                        vma_end   = align_pg_32(input);
                        make_vma_map(vma_start, vma_end);
                }
                else{
                        vma_start = align_pg_32(input);
                }
                start_end = !start_end;
        }

        return 0;
}

如您所见,程序接受虚拟地址范围,每个范围由开始和结束定义。然后通过对相邻页面授予不同的权限,将每个范围进一步细分为页面大小的 VMA。中断(使用 SIGINT)程序会触发对 munlockall() 的调用,并适当记录所述过程完成的时间。

现在,当我在 0x30000000-0x35000000 范围内使用 Linux 版本为 2.6.34 的飞思卡尔 e500mc 上运行它时,我得到的 munlockall() 总时间将近 45 秒。但是,如果我以随机顺序(即不一定增加地址)对较小的开始结束范围执行相同操作,以使页面总数(和锁定的 VMA)大致相同,请观察总 munlockall() 时间不超过 4 秒。

我在 x86_64 上用 Linux 2.6.34 尝试了同样的事情,我的程序根据 -m32 参数编译,看起来变化虽然不像 ppc 那样明显,但对于第一种情况仍然是 8 秒,不到一秒第二种情况。

我一方面在 Linux 2.6.10 上尝试了该程序,另一方面在 3.19 上尝试了该程序,似乎这些巨大的差异在那里不存在。更重要的是, munlockall() 总是在一秒钟内完成。

所以,不管是什么问题,似乎只存在于 2.6.34 版本的 Linux 内核附近。

【问题讨论】:

  • 你向进程发送哪个信号?
  • term 和 kill 似乎都可以。
  • 您说“我已经检查了分配那么多内存的程序...”,但这些程序是否使用mlock 将其所有页面锁定在 RAM 中?
  • @AnirbanGhoshal 一定要用2.6.34版本的linux内核吗?最简单的解决方案似乎是升级linux内核。
  • @Rootix - 是的。我想我们最终会这样做。但是,弄清楚 2.6.34 出了什么问题会很有趣。

标签: linux memory-management process linux-kernel operating-system


【解决方案1】:

您说 VM 是内部开发的。这是否意味着您可以访问源代码?我会首先检查它是否有任何东西可以阻止它立即终止以避免数据丢失。

否则,您能否尝试提供更多信息?您可能还想查看:https://unix.stackexchange.com/,因为它们更适合帮助解决 linux 内核可能遇到的任何问题。

【讨论】:

  • 谢谢。是的,我确实可以访问源代码。然而,导致这种延迟的不仅仅是处理过的信号。即使是 sigkill 也会这样做。我会采纳您的建议并在 Unix stackexchange 上发布类似的查询。
  • 好的,我很想看看你发现了什么。祝你好运。
  • 谢谢。 unix.stackexchange.com/questions/213072/…,仅供参考。
  • 在发这篇文章时,我只有 49 名声望...(比需要评论的少 1 名。)我真的希望对他有所帮助,随后选择尝试回答题。如果我违反了适当的礼仪,我深表歉意,我一定会在未来避免这样的违规行为。如果你愿意,我会删除答案。
猜你喜欢
  • 1970-01-01
  • 2020-11-08
  • 1970-01-01
  • 2022-11-05
  • 1970-01-01
  • 2020-02-28
  • 2013-02-06
相关资源
最近更新 更多