c – 如何在Linux上使用copy-on-write来处理共享内存

前端之家收集整理的这篇文章主要介绍了c – 如何在Linux上使用copy-on-write来处理共享内存前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我试着编写一个小应用程序来熟悉用户空间中的写时复制的概念.我已经阅读了 answer by MSalters,并认为只有当我开始使用mmap的文件来存储我的数据时它才会起作用.因为我不需要基于文件的持久性,所以我尝试用共享内存做同样的事情.首先我mmap’ed并初始化了一个shm fd,然后我用MAP_PRIVATE映射了第二个副本并再次从中读取.然而,只需从中读取就会导致内核复制整个内容,花费更多时间并占用内存的两倍.为什么不做COW?

这是我提出的用于说明行为的程序:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/mman.h>
  5. #include <fcntl.h>
  6. #include <assert.h>
  7.  
  8. static const size_t ARRAYSIZE = 1UL<<30;
  9.  
  10. void init(int* A)
  11. {
  12. for (size_t i = 0; i < ARRAYSIZE; ++i)
  13. A[i] = i;
  14. }
  15.  
  16. size_t agg(const int* A)
  17. {
  18. size_t sum = 0;
  19. for (size_t i = 0; i < ARRAYSIZE; ++i)
  20. sum += A[i];
  21. return sum;
  22. }
  23.  
  24. int main()
  25. {
  26. assert(sizeof(int) == 4);
  27. shm_unlink("/cowtest");
  28. printf("ARRAYSIZE: %lu\n",ARRAYSIZE);
  29. int fd = shm_open("/cowtest",O_RDWR | O_CREAT | O_TRUNC,0);
  30. if (fd == -1)
  31. {
  32. perror("Error allocating fd\n");
  33. return 1;
  34. }
  35. if (ftruncate(fd,sizeof(int) * ARRAYSIZE) == -1)
  36. {
  37. perror("Error ftruncate\n");
  38. return 1;
  39. }
  40. /* Open shm */
  41. int* A= (int*)mmap(NULL,sizeof(int) * ARRAYSIZE,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
  42. if (A == (int*)-1)
  43. {
  44. perror("Error mapping A to memory\n");
  45. return 1;
  46. }
  47. init(A);
  48.  
  49. /* Create cow copy */
  50. int* Acopy = (int*)mmap(NULL,PROT_READ,MAP_PRIVATE,0);
  51. if (Acopy == (int*)-1)
  52. {
  53. printf("Error mapping copy from file\n");
  54. return 1;
  55. }
  56.  
  57. /* Aggregate over A */
  58. size_t sumA = agg(A);
  59. size_t expected = (ARRAYSIZE * (ARRAYSIZE - 1)) >> 1;
  60. assert(expected == sumA);
  61.  
  62. /* Aggregate over Acopy */
  63. size_t sumCopy = agg(Acopy);
  64. assert(expected == sumCopy);
  65.  
  66.  
  67. shm_unlink("/cowtest");
  68. printf("Enter to exit\n");
  69. getchar();
  70. return 0;
  71. }

我用g -O3 -mtune = native -march = native -o shm-min shm-min.cpp -lrt编译它.

它创建的数组包含4GB的整数值.在终止程序之前,然后分配8GB的共享内存,在/ proc /< pid> / smaps中,您可以看到它在只读操作期间实际上执行了完整拷贝.我不知道为什么会那样做.这是内核错误吗?或者我错过了什么?

非常感谢任何见解.拉尔斯

编辑
这是Ubuntu 14.04(3.13.0-24)上/ proc /< pid> / smaps的相关内容

  1. 7f3b9b4ae000-7f3c9b4ae000 r--p 00000000 00:14 168154 /run/shm/cowtest (deleted)
  2. Size: 4194304 kB
  3. RSS: 4194304 kB
  4. Pss: 2097152 kB
  5. Shared_Clean: 0 kB
  6. Shared_Dirty: 4194304 kB
  7. Private_Clean: 0 kB
  8. Private_Dirty: 0 kB
  9. Referenced: 4194304 kB
  10. Anonymous: 0 kB
  11. AnonHugePages: 0 kB
  12. Swap: 0 kB
  13. KernelPageSize: 4 kB
  14. MMUPageSize: 4 kB
  15. Locked: 0 kB
  16. VmFlags: rd mr mw me sd
  17. 7f3c9b4ae000-7f3d9b4ae000 rw-s 00000000 00:14 168154 /run/shm/cowtest (deleted)
  18. Size: 4194304 kB
  19. RSS: 4194304 kB
  20. Pss: 2097152 kB
  21. Shared_Clean: 0 kB
  22. Shared_Dirty: 4194304 kB
  23. Private_Clean: 0 kB
  24. Private_Dirty: 0 kB
  25. Referenced: 4194304 kB
  26. Anonymous: 0 kB
  27. AnonHugePages: 0 kB
  28. Swap: 0 kB
  29. KernelPageSize: 4 kB
  30. MMUPageSize: 4 kB
  31. Locked: 0 kB
  32. VmFlags: rd wr sh mr mw me ms sd

解决方法

没有复制. smaps文件有一个提示
  1. Size: 4194304 kB
  2. RSS: 4194304 kB
  3. Pss: 2097152 kB

看看Pss是映射区域的实际大小的一半?那是因为它除以两个用法(Pss =比例共享大小).也就是说,您将相同的文件映射两次到不同的虚拟内存范围,但两个映射的底层物理页面相同.

要找出相关页面的物理地址,可以使用a tool here.将其保存为page-types.c,运行make page-types,然后./page-types -p< pid> -l -N.您将看到不同的虚拟地址(在第一列中)映射到相同的物理页面(在第二列中).

如果为第二个映射添加PROT_WRITE权限位,并调用init(Acopy),您将看到Pss跳转到4GB,并且相应页面的物理地址不再相同.

TL; DR COW工作.

猜你在找的C&C++相关文章