デフォルトでは、私は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ほど明確ではありませんが、変更が2番目ではない最初の場合はまだ8秒です。 1秒単位で。
一方では、Linux 2.6.10でもう一方では3.19でプログラムを試しましたが、これらの大きな違いは存在しないようです。さらに、 munlockall() は常に 1 秒以内に完了します。
したがって、問題が何であれ、Linuxカーネルバージョン2.6.34にのみ存在するようです。
ベストアンサー1
tmpfs
メモリをオーバーコミットする場合、ディスクには多くのメモリがある可能性があります。クローズを処理するためにコンテンツのページを付ける必要があるかもしれません。 mlock()
大量の追加メモリをディスクに強制的に割り当てることができます。ディスクがないと表示された場合は、おそらくWeb経由で読んでいます。
sar
すべての統計を収集するには、サーバーがダウンしている間実行してください。 (sar
デフォルトではインストールされない可能性があります。)5〜10秒間隔でデータをファイルにキャプチャするには、このオプションを使用します。その後、レジャー時にボトルネックが発生するリソースを調べることができます。
編集:あなたのコメントによると、ページテーブルにロックの問題が発生する可能性があります。mlock
電話は何通ですか?すべて必須ですか?プロセスを終了する前に、ロックされたメモリーセグメントのリストをダンプしてみてください。