我正在试验mmap
并附带以下示例代码:
int main() {
int fd;
char *filename = "/home/manu/file";
struct stat statbuf;
int i = 0;
char c = *(filename);
// Get file descriptor and file length
fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("fopen error");
}
if (fstat(fd, &statbuf) < 0) {
perror("fstat error");
}
printf("File size is %ld\n", statbuf.st_size);
// Map the file
char* mmapA = (char*) mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE,
fd, 0);
if (mmapA == MAP_FAILED) {
perror("mmap error");
return 1;
}
// Touch all the mapped pages
while (i < statbuf.st_size) {
c = mmapA[i];
i++;
}
c++;
// Close file descriptor
if (close(fd) == -1) {
perror("close");
return 1;
}
//Unmap file
munmap(mmapA, statbuf.st_size);
return EXIT_SUCCESS;
}
文件大小为137948字节= 134,7千字节。 为了检查程序的内存,我使用top,主要是RES和VIRT列。我在三个不同的地方寻找这些价值观:
mmap
致电mmap
致电top报告的值是
1964 - 1828 = 136,我猜以千字节为单位,因此与文件的大小完全匹配。
但我无法理解508 - 248 = 260的RES差异。为什么它与虚拟内存大小和文件大小不同?
答案 0 :(得分:2)
有一件事是肯定的:结果取决于系统的状态,而不仅仅取决于正在运行的应用程序。在我的机器上,我运行程序的前两次RES的增加是136 kB,但随后的运行根本没有任何增加 - 可能是操作系统已经将整个文件放在缓存中。有趣的是,这些价值观在运行之间存在显着差异。在第一次运行中,RES的跳转从344到480 kB,但后者运行的RES值始终为348 kB。 SHR也发生了类似的变化:第一次跳转为136 kB,之后没有变化。
我可以通过覆盖文件来强制原始案例(使用136 kB跳转),该文件稍后在运行应用程序之前使用dd
用零映射。
我查看了pmaps
输出,但在两种情况下完全相同,并且在调用mmap()
后没有更改。
我无法在这里重现超大的RES跳转,但这是你可以做的。假设您的二进制文件编译为a.out
。在mmap()
之后立即插入10秒睡眠,在munmap()
之前再睡10秒钟。这给出了转储有趣信息的时间窗口。我们将从/proc
读取确切文件驻留在内存中的内容。为此,请在终端中打开两个标签,一次运行
./a.out
然后立即在另一个标签中:
for ((i=0;i<4;i++)); do cat /proc/$(ps -fe | egrep '[a]\.out' | awk '{print $2}')/smaps > smaps.$i; sleep 5; done
这将在四个单独的文件中创建程序地图状态的4个快照。其中一个连续编号的快照之间的差异应该显示RES大小激增期间的变化。在示例运行期间我的机器上,差异在快照1和2之间,并且更改是[注意我更改了映射文件的名称,但这里并不重要]:
user@machine:~$ diff -u smaps.{1,2}
--- smaps.1 2012-04-19 00:01:46.000000000 +0200
+++ smaps.2 2012-04-19 00:01:51.000000000 +0200
@@ -84,13 +84,13 @@
MMUPageSize: 4 kB
b782f000-b7851000 r--p 00000000 08:05 429102 /tmp/tempfile
Size: 136 kB
-Rss: 0 kB
-Pss: 0 kB
+Rss: 136 kB
+Pss: 136 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
-Private_Clean: 0 kB
+Private_Clean: 136 kB
Private_Dirty: 0 kB
-Referenced: 0 kB
+Referenced: 136 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
究竟应该发生什么:映射文件最初根本不驻留,后来居住了136 kB。
在您的系统上,diff应该引导您到RES中的其他更改源 - 您应该能够找到Rss
值更改的其他文件的名称。某些条目不是文件,而是其他内存区域,例如,您可能会找到[heap]
和[stack]
等标记。这也应该证明或反驳nos关于加载系统库和堆栈使用量增长的建议。