2011-08-12 23 views
10

Tôi có một chương trình mẫu nhỏ chỉ đơn giản là fopen s tệp và sử dụng fgets để đọc. Sử dụng strace, tôi nhận thấy rằng lệnh gọi đầu tiên tới fgets chạy một cuộc gọi hệ thống mmap và sau đó đọc các cuộc gọi hệ thống được sử dụng để thực sự đọc nội dung của tệp. trên fclose, tệp là munmap ed. Nếu tôi thay vì mở đọc tập tin với mở/đọc trực tiếp, điều này rõ ràng là không xảy ra. Tôi tò mò về mục đích của mmap này là gì và mục đích của nó là gì.Tại sao fopen/fgets sử dụng cả mmap và đọc các cuộc gọi hệ thống để truy cập dữ liệu?

Trên hệ thống dựa trên Linux 2.6.31 của tôi, khi có nhu cầu bộ nhớ ảo nặng, các đôi khi một vài giây sẽ bị treo trong một vài giây và có vẻ như không cần thiết.

Đoạn mã ví dụ:

#include <stdlib.h> 
#include <stdio.h> 
int main() 
{ 
    FILE *f; 
    if (NULL == (f=fopen("foo.txt","r"))) 
    { 
    printf ("Fail to open\n"); 
    } 
    char buf[256]; 
    fgets(buf,256,f); 
    fclose(f); 
} 

Và đây là sản phẩm có liên quan strace khi mã trên được điều hành:

open("foo.txt", O_RDONLY)    = 3 
fstat64(3, {st_mode=S_IFREG|0644, st_size=9, ...}) = 0 
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb8039000 
read(3, "foo\nbar\n\n"..., 4096)  = 9 
close(3)        = 0 
munmap(0xb8039000, 4096)    = 0 

Trả lời

15

Nó không phải là tập tin đó là mmap 'ed - trong trường hợp này mmap được sử dụng ẩn danh (không phải trên một tệp), có thể phân bổ bộ nhớ cho bộ đệm mà kết quả đọc sẽ sử dụng.

malloc trong thực tế, kết quả trong cuộc gọi đến mmap. Tương tự, số munmap tương ứng với cuộc gọi đến free.

+1

Thú vị. Vì vậy, từ điều này tôi thu thập rằng tất cả các hoạt động đọc trên FILE * không thực sự đọc vào bộ đệm được cung cấp, nhưng vào một bộ đệm bổ sung được phân bổ trên đống và sau đó sao chép vào bộ đệm của tôi. Ngoài ra, hiện malloc luôn luôn dẫn đến một cuộc gọi đến mmap? Tôi luôn nghĩ rằng heap được quản lý cục bộ trong không gian người dùng và các cuộc gọi hệ thống chỉ được thực hiện nếu thêm bộ nhớ cần thiết để được thêm vào không gian địa chỉ tiến trình. Tôi cũng luôn nghĩ rằng sbrk/brk đã được sử dụng cho việc này, chứ không phải là mmap. – bdk

+5

@bdk: Có, các chức năng tập tin từ thư viện chuẩn (không phải các cuộc gọi hệ thống) đều giữ bộ đệm của riêng chúng để khi bạn gọi 'fgets (buf, 1, f)' liên tục trong một vòng lặp, nó không dẫn đến hàng trăm cuộc gọi hệ thống 'đọc'. 'malloc' dẫn đến' mmap' khi nó không có nhiều không gian hơn trong vùng người dùng - ví dụ, 'malloc (8)' đầu tiên có thể dẫn đến 'mmap (4096)', và hậu quả là 'malloc (8) ''s sẽ trả về con trỏ tới vùng đã được cấp phát cho đến khi nó bị cạn kiệt. –

+0

Cảm ơn! Giải thích nó. Mỗi khi tôi sử dụng strace để cố gắng theo dõi một cái gì đó xuống tôi kết thúc học một cái gì đó mới. – bdk

1

từ những gì tôi đã đọc chức năng ánh xạ bộ nhớ rất hữu ích trong khi xử lý các tệp lớn. bây giờ định nghĩa của lớn là cái gì tôi không có ý tưởng về. nhưng có cho các tệp lớn, chúng nhanh hơn đáng kể so với các cuộc gọi i/o 'đệm'.

trong ví dụ mà bạn đã đăng tôi nghĩ rằng tệp được mở bởi hàm open() và mmap được sử dụng để cấp phát bộ nhớ hoặc cái gì khác.

từ cú pháp của hàm mmap này có thể thấy rõ:

void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);

tham số cuối cùng thứ hai có mô tả tập tin đó nên không âm. trong khi theo dõi ngăn xếp, nó là -1

+0

Điều này là sai. Trên POSIX stdio không thể được thực hiện với 'mmap' vì ngữ nghĩa sai khi tệp bị cắt ngắn (nó sẽ bị lỗi với' SIGBUS' thay vì đưa ra lỗi). Các 'mmap' OP được hỏi về không phải là một bản đồ của tập tin; nó chỉ đơn giản là phân bổ bộ nhớ ẩn danh. –

+0

đó là những gì tôi đã nói "mmap được sử dụng để phân bổ bộ nhớ hoặc cái gì khác" ... tôi đã không nói mmap được sử dụng cho mmapping 'các' tập tin. –

+0

Ồ, tôi đã đọc sai "hữu ích" là "cũ". Lấy làm tiếc! –

5

mmap không ánh xạ tệp; thay vào đó, nó cấp phát bộ nhớ cho bộ đệm stdio FILE. Thông thường malloc sẽ không sử dụng mmap để phân phối một phân bổ nhỏ như vậy, nhưng có vẻ như việc thực hiện stdio của glibc đang sử dụng trực tiếp mmap để nhận bộ đệm. Điều này có thể đảm bảo rằng nó được canh lề trang (mặc dù posix_memalign có thể đạt được điều tương tự) và/hoặc để đảm bảo đóng tệp trả về bộ nhớ đệm cho hạt nhân. Tôi đặt câu hỏi về tính hữu ích của việc sắp xếp trang bộ đệm. Có lẽ nó cho hiệu suất, nhưng tôi không thể nhìn thấy bất kỳ cách nào nó sẽ giúp trừ khi các tập tin bù đắp bạn đang đọc từ cũng được liên kết trang, và thậm chí sau đó nó có vẻ như một tối ưu hóa vi sai đáng ngờ.

Các vấn đề liên quan