• 内存-虚拟地址到物理内存地址转换


    虚拟地址的位数

    1. [root@new ~]# cat /proc/cpuinfo | grep virtu | tail -1
    2. address sizes : 46 bits physical, 48 bits virtual

    高性能C++之虚拟内存_哔哩哔哩_bilibili

    第零层,每一项是4KB,每一个大项512个4KB是2MB,

    第一层,每一项是2MB,每一大项是512个2MB是1GB

    第二层,每一项是1GB,每一个大项是512个1GB是512GB

    第三层,每一项是512GB,512个526GB是256TB

    下在内核模块:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. struct Page
    8. {
    9. uint64_t address;
    10. // 页表中每一项是一个64bit的页表条目
    11. uint64_t entry[512];
    12. };
    13. uint64_t get_phys_address(uint64_t entry)
    14. {
    15. // 获得物理地址,是48bit的真是物理地址
    16. // 第63位置有个1,低11个位置都是1,总共是12个1
    17. // ~mask是总共
    18. static const uint64_t mask = (1LL << 63) | ((1 << 12) - 1);
    19. return entry & ~mask;
    20. }
    21. bool writable(uint64_t entry)
    22. {
    23. return (entry & (1 << 1)) != 0;
    24. }
    25. bool executable(uint64_t entry)
    26. {
    27. return (entry & (1LL << 63)) == 0;
    28. }
    29. bool user_mode(uint64_t entry)
    30. {
    31. return (entry & (1 << 2)) != 0;
    32. }
    33. void print_entry(FILE* fp, int level, uint64_t entry, uint64_t virtual_address)
    34. {
    35. fprintf(fp, "%d\t0x%016lx\t0x%016lx\t%d\t%d\t%d\n", level, get_phys_address(entry), virtual_address, writable(entry), executable(entry), user_mode(entry));
    36. }
    37. void dump(FILE* fp, const Page*& page, int level, uint64_t virtual_address)
    38. {
    39. const Page* cur_page = page++;
    40. // 每页表项都是512个
    41. for (int i = 0; i < 512; i++)
    42. {
    43. // 页表条目
    44. const uint64_t entry = cur_page->entry[i];
    45. // 获取当前的页表条目对应的虚拟地址
    46. const uint64_t child_virtual_address = (virtual_address << 9) | i;
    47. if (level > 0)
    48. {
    49. if (entry & 1)
    50. {
    51. if (!(entry&(1<<7)))
    52. {
    53. // 继续递归下一层
    54. dump(fp, page, level - 1, child_virtual_address);
    55. }
    56. else
    57. {
    58. // 打印当前页表条目对应的信息
    59. print_entry(fp, level, entry, child_virtual_address << (level * 9 + 12));
    60. }
    61. }
    62. }
    63. else
    64. {
    65. // 第0层是,512个4KB的页表条目
    66. if (entry)
    67. {
    68. print_entry(fp, level, entry, child_virtual_address << 12);
    69. }
    70. }
    71. }
    72. }
    73. void dump_pagetable(FILE* fp)
    74. {
    75. std::ifstream ifs("/proc/page_table_3", std::ios::binary);
    76. if (!ifs)
    77. {
    78. return;
    79. }
    80. std::string content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
    81. const Page* page = (const Page*)&content[0];
    82. const Page* end_page = (const Page*)(&content[0] + content.length());
    83. dump(fp, page, 3, 0);
    84. std::cout << (const void*)end_page << '\t' << (const void*)page << std::endl;
    85. std::flush(std::cout);
    86. }
    87. int main()
    88. {
    89. const int N = 1024 * 1024 * 8;
    90. // 是否开启大页
    91. const bool hugetable = true;
    92. const bool do_fork = false;
    93. char* m = (char*)mmap(NULL, N, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED | (hugetable ? MAP_HUGETLB: 0), -1, 0);
    94. std::cout << *m << std::endl;
    95. FILE* fp = NULL;
    96. if (do_fork)
    97. {
    98. pid_t pid = fork();
    99. if (pid == 0)
    100. {
    101. fp = fopen("/home/fractal/lecture/child.log", "w");
    102. }
    103. else
    104. {
    105. fp = fopen("/home/fractal/lecture/father.log", "w");
    106. }
    107. }
    108. else
    109. {
    110. fp = fopen("/home/fractal/lecture/father.log", "w");
    111. }
    112. fprintf(fp, "mmap address: %p\n", m);
    113. dump_pagetable(fp);
    114. fclose(fp);
    115. while (true)
    116. {
    117. usleep(10000);
    118. }
    119. return 0;
    120. }

    1.只有向mmap申请的地址写入东西,操作系统才会分配物理地址

    2.是大页,系统需要预先分配大页

    3.for父子进程公用的内存页,被设置为不可写。子进程,如果往页写入东西,会出发异常,操作系统会捕获,分配新的物理内容,把内容copy一份(孩子的),并且设置为可写。父亲的页面还是不可以写入的。fork机制可以省内存,相对于多线程,不会有数据冲突。多线程需要考虑数据冲突。

  • 相关阅读:
    从javascript到vue再到react的演变
    C++ 继承多态的运用
    (附源码)springboot篮球场地预约系统 毕业设计 345655
    MyBatis学习:按照位置传递参数
    计算机竞赛 深度学习乳腺癌分类
    数据库中没有外键约束的 9 个原因
    【简单讲解下epoll】
    texlive 2022安装与使用
    数据结构--排序(1)
    多线程学习笔记-3.并发容器
  • 原文地址:https://blog.csdn.net/INGNIGHT/article/details/134077444