기본적으로 저는 PowerPC(Freescale e500mc)에서 Linux 2.6.34를 사용하고 있습니다. 약 2.25G의 mlocked 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를 사용하는 freescale e500mc에서 실행하면 총 munlockall() 시간이 거의 45초가 됩니다. 그러나 전체 페이지 수(및 잠긴 VMA)가 거의 동일하도록 무작위 순서로 더 작은 시작-끝 범위로 동일한 작업을 수행하면(즉, 반드시 주소를 늘릴 필요는 없음) munlockall( )은 4초를 넘지 않습니다.
Linux 2.6.34를 사용하여 x86_64에서 동일한 작업을 시도했으며 내 프로그램은 -m32 매개변수에 따라 컴파일되었습니다. ppc만큼 명확하지는 않지만 변경 사항이 두 번째가 아닌 첫 번째 경우에는 여전히 8초인 것 같습니다. 1초 단위로.
한편으로는 Linux 2.6.10에서 다른 한편으로는 3.19에서 프로그램을 시도했는데 이러한 큰 차이점은 존재하지 않는 것 같습니다. 게다가 munlockall()은 항상 1초 이내에 완료됩니다.
따라서 문제가 무엇이든 Linux 커널 버전 2.6.34에만 존재하는 것 같습니다.
답변1
tmpfs
메모리를 오버커밋하는 경우 디스크에 많은 메모리가 있을 수 있습니다. 닫기를 처리하기 위해 콘텐츠의 페이지를 매겨야 할 수도 있습니다. mlock()
많은 양의 추가 메모리가 디스크에 강제로 할당될 수 있습니다. 디스크가 없다고 표시하면 아마도 웹을 통해 읽고 있는 것입니다.
sar
모든 통계를 수집하려면 서버가 다운된 동안 실행하세요. ( sar
기본적으로 설치되지 않을 수 있습니다.) 5~10초 간격으로 데이터를 파일로 캡처하려면 이 옵션을 사용합니다. 그런 다음 여가 시간에 병목 현상이 발생하는 리소스를 검사할 수 있습니다.
편집: 귀하의 의견에 따르면 페이지 테이블에 잠금 문제가 발생할 수 있습니다. mlock
전화는 몇 통이나 하셨나요? 모두 필수인가요? 프로세스를 종료하기 전에 잠긴 메모리 세그먼트 목록을 덤프해 보십시오.