您当前的位置:首页 > 电脑百科 > 软件技术 > 操作系统 > linux

Linux内核虚拟内存管理之匿名映射缺页异常分析

时间:2020-09-10 10:48:48  来源:  作者:

韩传华,就职于南京大鱼半导体有限公司,主要从事linux相关系统软件开发工作,负责Soc芯片BringUp及系统软件开发,乐于分享喜欢学习,喜欢专研Linux内核源代码。

前面讲到过写时复制缺页异常(COW),一般用于父子进程之间共享页,而我们会常见一种缺页异常是匿名映射缺页异常,今天我们就来讨论下这种缺页异常,让大家彻底理解它。注:本文使用linux-5.0内核源代码。文章分为以下几节内容:

1.匿名映射缺页异常的触发情况 2.0页是什么?为什么使用0页?

3.源代码分析

3.1 触发条件

3.2 第一次读匿名页

3.3 第一次写匿名页

3.4 读之后写匿名页

4.应用层实验

5.总结

在讲解匿名映射缺页异常之前我们先要了解以下什么是匿名页?与匿名页相对应的是文件页,文件页我们应该很好理解,就是映射文件的页,如:通过mmap映射文件到虚拟内存然后读文件数据,进程的代码数据段等,这些页有后备缓存也就是块设备上的文件,而匿名页就是没有关联到文件的页,如:进程的堆、栈等。还有一点需要注意:下面讨论的都是私有的匿名页的情况,共享匿名页在内核演变为文件映射缺页异常(伪文件系统),后面有机会我们会讲解,感兴趣的小伙伴可以看一看mmap的代码实现对共享匿名页的处理。

一,匿名映射缺页异常的触发情况

前面我们讲解了什么是匿名页,那么思考一下什么情况下会触发匿名映射缺页异常呢?这种异常对于我们来说非常常见:

1.当我们应用程序使用malloc来申请一块内存(堆分配),在没有使用这块内存之前,仅仅是分配了虚拟内存,并没有分配物理内存,第一次去访问的时候才会通过触发缺页异常来分配物理页建立和虚拟页的映射关系。

2.当我们应用程序使用mmap来创建匿名的内存映射的时候,页同样只是分配了虚拟内存,并没有分配物理内存,第一次去访问的时候才会通过触发缺页异常来分配物理页建立和虚拟页的映射关系。

3.当函数的局部变量比较大,或者是函数调用的层次比较深,导致了当前的栈不够用了,这个时候需要扩大栈。当然了上面的这几种场景对应应用程序来说是透明的,内核为用户程序做了大量的处理工作,下面几节会看到如何处理。

二,0页是什么?为什么使用0页?

这里为什么会说到0页呢?什么是0页呢?是地址为0的页吗?答案是:系统初始化过程中分配了一页的内存,这段内存全部被填充0。下面我们来看下0页如何分配的:在arch/arm64/mm/mmu.c中:

    61 /*
    62  * Empty_zero_page is a special page that is used for zero-initialized data
    63  * and COW.
    64  */
    65 unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss;
    66 EXPORT_SYMBOL(empty_zero_page);

可以看到定义了一个全局变量,大小为一页,页对齐到bss段,所有这段数据内核初始化的时候会被清零,所有称之为0页。

那么为什么使用0页呢?一个是它的数据都是被0填充,读的时候数据都是0,二是节约内存,匿名页面第一次读的时候数据都是0都会映射到这页中从而节约内存(共享0页),那么如果有进程要去写这个这个页会怎样呢?答案是发生COW重新分配页来写

三,源代码分析

3.1 触发条件

当第一节中的触发情况发生的时候,处理器就会发生缺页异常,从处理器架构相关部分过渡到处理器无关部分,最终到达handle_pte_fault函数:

  3742 static vm_fault_t handle_pte_fault(struct vm_fault *vmf)
  3743 {
  3744         pte_t entry;
  ...
  3782         if (!vmf->pte) {
  3783                 if (vma_is_anonymous(vmf->vma))
  3784                         return do_anonymous_page(vmf);
  3785                 else
  3786                         return do_fault(vmf);
  3787         }

3782和3783行是匿名映射缺页异常的触发条件:

1.发生缺页的地址所在页表项不存在。

2.是匿名页发生的,即是vma->vm_ops为空。

当满足这两个条件的时候就会调用do_anonymous_page函数来处理匿名映射缺页异常。

  2871 /*
  2872  * We enter with non-exclusive mmap_sem (to exclude vma changes,
  2873  * but allow concurrent faults), and pte mApped but not yet locked.
  2874  * We return with mmap_sem still held, but pte unmapped and unlocked.
  2875  */
  2876 static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
  2877 {
  2878         struct vm_area_struct *vma = vmf->vma;
  2879         struct mem_cgroup *memcg;
  2880         struct page *page;
  2881         vm_fault_t ret = 0;
  2882         pte_t entry;
  2883 
  2884         /* File mapping without ->vm_ops ? */
  2885         if (vma->vm_flags & VM_SHARED)
  2886                 return VM_FAULT_SIGBUS;
  2887 
  2888         /*
  2889         ¦* Use pte_alloc() instead of pte_alloc_map().  We can't run
  2890         ¦* pte_offset_map() on pmds where a huge pmd might be created
  2891         ¦* from a different thread.
  2892         ¦*
  2893         ¦* pte_alloc_map() is safe to use under down_write(mmap_sem) or when
  2894         ¦* parallel threads are excluded by other means.
  2895         ¦*
  2896         ¦* Here we only have down_read(mmap_sem).
  2897         ¦*/
  2898         if (pte_alloc(vma->vm_mm, vmf->pmd))
  2899                 return VM_FAULT_OOM;
  2904 
  ...

2885行判断:发生缺页的vma是否为私有映射,这个函数处理的是私有的匿名映射

2898行 如何页表不存在则分配页表(有可能缺页地址的页表项所在的直接页表不存在)。

3.2 第一次读匿名页情况

  ...
  2905         /* Use the zero-page for reads */
  2906         if (!(vmf->flags & FAULT_FLAG_WRITE) &&
  2907                         !mm_forbids_zeropage(vma->vm_mm)) {
  2908                 entry = pte_mkspecial(pfn_pte(my_zero_pfn(vmf->address),
  2909                                                 vma->vm_page_prot));
  2910                 vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd,
  2911                                 vmf->address, &vmf->ptl);
  2912                 if (!pte_none(*vmf->pte))
  2913                         goto unlock;
  2914                 ret = check_stable_address_space(vma->vm_mm);
  2915                 if (ret)
  2916                         goto unlock;
  2917                 /* Deliver the page fault to userland, check inside PT lock */
  2918                 if (userfaultfd_missing(vma)) {
  2919                         pte_unmap_unlock(vmf->pte, vmf->ptl);
  2920                         return handle_userfault(vmf, VM_UFFD_MISSING);
  2921                 }
  2922                 goto setpte;
  2923         }
  ...  2968 setpte:
  2969         set_pte_at(vma->vm_mm, vmf->address, vmf->pte, entry);

2906到2923行是处理的是私有匿名页读的情况:这里就会用到我们上面将的0页了。

2906和 2907行判断是否是由于读操作导致的缺页而且没有禁止0页。

2908-2909行是核心部分:设置页表项的值映射到0页

我们主要研究这个语句:pfn_pte用来将页帧号和页表属性拼接为页表项值:

arch/arm64/include/asm/pgtable.h:
77 #define pfn_pte(pfn,prot)       
78         __pte(__phys_to_pte_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))

是将pfn左移PAGE_SHIFT位(一般为12bit),或上pgprot_val(prot)

先看my_zero_pfn:

include/asm-generic/pgtable.h:
   875 static inline unsigned long my_zero_pfn(unsigned long addr)
   876 {
   877         extern unsigned long zero_pfn;
   878         return zero_pfn;
   879 }
mm/memory.c:   
126 unsigned long zero_pfn __read_mostly;   
127 EXPORT_SYMBOL(zero_pfn);   
128    
129 unsigned long highest_memmap_pfn __read_mostly;   
130    
131 /*   
132  * CONFIG_MMU architectures set up ZERO_PAGE in their paging_init()   
133  */   
134 static int __init init_zero_pfn(void)   1
                                  35 {   136         zero_pfn = page_to_pfn(ZERO_PAGE(0));   137         return 0;   138 }   139 core_initcall(init_zero_pfn);

||

/

arch/arm64/include/asm/pgtable.h:
   54 /*
   55  * ZERO_PAGE is a global shared page that is always zero: used
   56  * for zero-mapped memory areas etc..
   57  */
   58 extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
   59 #define ZERO_PAGE(vaddr)        phys_to_page(__pa_symbol(empty_zero_page))

最终我们看到使用的就是内核初始化设置的empty_zero_page这个0页得到页帧号。再看看pfn_pte的第二个参数vma->vm_pageprot,这是vma的访问权限,在做内存映射mmap的时候会被设置。

那么我们想知道的时候是什么时候0页被设置为了只读属性的(也就是页表项何时被设置为只读)

我们带着这个问题去在内核代码中寻找答案。其实代码看到这里一般看不到头绪,但是我们要知道何时vma的vm_page_prot成员被设置的,如何被设置的,有可能就能找到答案。

我们到mm/mmap.c中去寻找答案:我们以do_brk_flags函数为例,这是设置堆的函数我们关注到3040行设置了vm_page_prot:

3040         vma->vm_page_prot = vm_get_page_prot(flags);  

||

/

  110 pgprot_t vm_get_page_prot(unsigned long vm_flags)
   111 {
   112         pgprot_t ret = __pgprot(pgprot_val(protection_map[vm_flags &
   113                                 (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]) |
   114                         pgprot_val(arch_vm_get_page_prot(vm_flags)));
   115 
   116         return arch_filter_pgprot(ret);
   117 }
   118 EXPORT_SYMBOL(vm_get_page_prot);

vm_get_page_prot函数会根据传递来的vmflags是否为VMREAD|VMWRITE|VMEXEC|VMSHARED来转换为保护位组合,继续往下看

||

/

   78 /* description of effects of mapping type and prot in current implementation.
    79  * this is due to the limited x86 page protection hardware.  The expected
    80  * behavior is in parens:
    81  *
    82  * map_type     prot
    83  *              PROT_NONE       PROT_READ       PROT_WRITE      PROT_EXEC
    84  * MAP_SHARED   r: (no) no      r: (yes) yes    r: (no) yes     r: (no) yes
    85  *              w: (no) no      w: (no) no      w: (yes) yes    w: (no) no
    86  *              x: (no) no      x: (no) yes     x: (no) yes     x: (yes) yes
    87  *
    88  * MAP_PRIVATE  r: (no) no      r: (yes) yes    r: (no) yes     r: (no) yes
    89  *              w: (no) no      w: (no) no      w: (copy) copy  w: (no) no
    90  *              x: (no) no      x: (no) yes     x: (no) yes     x: (yes) yes
    91  *
    92  * On arm64, PROT_EXEC has the following behaviour for both MAP_SHARED and
    93  * MAP_PRIVATE:
    94  *                                                              r: (no) no
    95  *                                                              w: (no) no
    96  *                                                              x: (yes) yes
    97  */
    98 pgprot_t protection_map[16] __ro_after_init = {
    99         __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
   100         __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
   101 };

protection_map数组定义了从P000到S111一共16种组合,P表示私有(Private),S表示共享(Share),后面三个数字依次为可读、可写、可执行,如:_S010表示共享、不可读、可写、不可执行。

||

/

arch/arm64/include/asm/pgtable-prot.h:
   93 #define PAGE_NONE               __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
   94 #define PAGE_SHARED             __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
   95 #define PAGE_SHARED_EXEC        __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE)
   96 #define PAGE_READONLY           __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
   97 #define PAGE_READONLY_EXEC      __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN)
   98 #define PAGE_EXECONLY           __pgprot(_PAGE_DEFAULT | PTE_RDONLY | PTE_NG | PTE_PXN)
   99 
  100 #define __P000  PAGE_NONE
  101 #define __P001  PAGE_READONLY
  102 #define __P010  PAGE_READONLY
  103 #define __P011  PAGE_READONLY
  104 #define __P100  PAGE_EXECONLY
  105 #define __P101  PAGE_READONLY_EXEC
  106 #define __P110  PAGE_READONLY_EXEC
  107 #define __P111  PAGE_READONLY_EXEC
  108 
  109 #define __S000  PAGE_NONE
  110 #define __S001  PAGE_READONLY
  111 #define __S010  PAGE_SHARED
  112 #define __S011  PAGE_SHARED
  113 #define __S100  PAGE_EXECONLY
  114 #define __S101  PAGE_READONLY_EXEC
  115 #define __S110  PAGE_SHARED_EXEC
  116 #define __S111  PAGE_SHARED_EXEC

可以发现对于私有的映射只有只读(PTE_RDONLY)没有可写属性(PTE_WRITE)105-107行 ,虽然之前设置的时候是设置了可写(VM_WRITE)!而对应共享映射则会有可写属性。

而这个被设置的保护位组合最终会在缺页异常中被设置到页表中:上面说到的do_anonymous_page函数:

2908                 entry = pte_mkspecial(pfn_pte(my_zero_pfn(vmf->address),
2909                                                 vma->vm_page_prot));

对于私有匿名映射的页,假设设置的vmflags为VMREAD|VMWRITE则对应的保护位组合为:P110即为PAGE_READONLY_EXEC=pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PT_ENG | PTE_PXN)不会设置为可写。

所以就将其页表设置为了只读!!!

2922行 跳转到setpte去将设置好的页表项值填写到页表项中。

当匿名页读之后再次去写时候会由于页表属性为只读导致COW缺页异常,详将COW相关文章,再此不在赘述。下面用图说话:

Linux内核虚拟内存管理之匿名映射缺页异常分析

 

3.3 第一次写匿名页的情况

接着do_anonymous_page函数继续往下分析:

2876 static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
  2877 {
  ...
  2924 
  2925         /* Allocate our own private page. */
  2926         if (unlikely(anon_vma_prepare(vma)))
  2927                 goto oom;
  2928         page = alloc_zeroed_user_highpage_movable(vma, vmf->address);
  2929         if (!page)
  2930                 goto oom;
  2931 
  2932         if (mem_cgroup_try_charge_delay(page, vma->vm_mm, GFP_KERNEL, &memcg,
  2933                                         false))
  2934                 goto oom_free_page;
  2935 
  2936         /*
  2937         ¦* The memory barrier inside __SetPageUptodate makes sure that
  2938         ¦* preceeding stores to the page contents become visible before
  2939         ¦* the set_pte_at() write.
  2940         ¦*/
  2941         __SetPageUptodate(page);
  2942 
  2943         entry = mk_pte(page, vma->vm_page_prot);
  2944         if (vma->vm_flags & VM_WRITE)
  2945                 entry = pte_mkwrite(pte_mkdirty(entry));
 2946 
  2947         vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd, vmf->address,
  2948                         &vmf->ptl);
  2949         if (!pte_none(*vmf->pte))
  2950                 goto release;
  2951 
  2952         ret = check_stable_address_space(vma->vm_mm);
  2953         if (ret)
  2954                 goto release;
  2955 
  2956         /* Deliver the page fault to userland, check inside PT lock */
  2957         if (userfaultfd_missing(vma)) {
  2958                 pte_unmap_unlock(vmf->pte, vmf->ptl);
  2959                 mem_cgroup_cancel_charge(page, memcg, false);
  2960                 put_page(page);
  2961                 return handle_userfault(vmf, VM_UFFD_MISSING);
  2962         }
  2963 
  2964         inc_mm_counter_fast(vma->vm_mm, MM_ANONPAGES);
  2965         page_add_new_anon_rmap(page, vma, vmf->address, false);
  2966         mem_cgroup_commit_charge(page, memcg, false, false);
  2967         lru_cache_add_active_or_unevictable(page, vma);
  2968 setpte:
  2969         set_pte_at(vma->vm_mm, vmf->address, vmf->pte, entry);
  2970 
  2971         /* No need to invalidate - it was non-present before */
  2972         update_mmu_cache(vma, vmf->address, vmf->pte);
  2973 unlock:
  2974         pte_unmap_unlock(vmf->pte, vmf->ptl);
  2975         return ret;
  2976 release:
  2977         mem_cgroup_cancel_charge(page, memcg, false);
  2978         put_page(page);
  2979         goto unlock;
  2980 oom_free_page:
  2981         put_page(page);
  2982 oom:
  2983         return VM_FAULT_OOM;
  2984 }

当判断不是读操作导致的缺页的时候,则是写操作造成,处理写私有的匿名页情况,请记住这依然是第一次访问这个匿名页只不过是写访问而已

2928 行会分配一个高端 可迁移的 被0填充的物理页。2941 设置页中数据有效 2943 使用页帧号和vma的访问权限设置页表项值(注意:这个时候页表项属性依然为只读)。

2944-2945行 如果vma可写,则设置页表项值为脏且*可写*(这个时候才设置为可写)。

2964行 匿名页计数统计 2965行 添加到匿名页的反向映射中 2967行 添加到lru链表 2969 将设置好的页表项值填充到页表项中。

下面用图说话:

Linux内核虚拟内存管理之匿名映射缺页异常分析

 

3.4 读之后写匿名页

读之后写匿名页,其实已经很简单了,那就是发生COW写时复制缺页。下面依然看图说话:

Linux内核虚拟内存管理之匿名映射缺页异常分析

 

四,应用层实验

实验1:主要体验下内核的按需分配页策略!实验代码:mmap映射10 * 4096 * 4096/1M=160M内存空间,映射和写页前后获得内存使用情况:

   1 #include <stdio.h>
    2 #include <stdlib.h>
    3 #include <sys/mman.h>
    4 #include <unistd.h>
    5 
    6 
    7 #define MAP_LEN (10 * 4096 * 4096)
    8 
    9 int main(int argc, char **argv)
   10 {
   11         char *p;
   12         int i;
   13 
   14 
   15         puts("before mmap ->please exec: free -mn");
   16         sleep(10);
   17         p = (char *)mmap(0, MAP_LEN, PROT_READ |PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   18 
   19         puts("after mmap ->please exec: free -mn");
   20         puts("before write....n");
   21         sleep(10);
   22 
   23         for(i=0;i <4096 *10; i++)
   24                 p[4096 * i] = 0x55;
   25 
   26 
   27         puts("after write ->please exec: free -mn");
   28 
   29         pause();
   30 
   31         return 0;
   32 }             

执行结果:

出现“before mmap ->please exec: free -m”打印后执行:

$ free -m
              总计         已用        空闲      共享    缓冲/缓存    可用
内存:15921        6561         462         796        8897        8214
交换:16290         702       15588

出现“after mmap ->please exec: free -m”打印后执行:

$ free -m
              总计         已用        空闲      共享    缓冲/缓存    可用
内存:15921        6565         483         771        8872        8236
交换:16290         702       15588

出现“after write ->please exec: free -m”后执行:

$:~/study/user_test/page-fault$ free -m
              总计         已用        空闲      共享    缓冲/缓存    可用
内存:15921        6727         322         770        8871        8076
交换:16290         702       15588

我们只关注已用内存,可以发现映射前后基本上已用内存没有变化(考虑到其他内存申请情况存在,也会有内存变化)是6561M和6565M,说明mmap的时候并没有分配物理内存,写之后发现内存使用为6727M, 6727-6565=162M与我们mmap的大小基本一致,说明了匿名页实际写的时候才会分配等量的物理内存。

 

实验2:主要体验下匿名页读之后写内存页申请情况 实验代码:mmap映射10 * 4096 * 4096/1M=160M内存空间,映射、读然后写页前后获得内存使用情况:

    1 #include <stdio.h>
    2 #include <stdlib.h>
    3 #include <sys/mman.h>
    4 #include <unistd.h>
    5 
    6 
    7 #define MAP_LEN (10 * 4096 * 4096)
    8 
    9 int main(int argc, char **argv)
   10 {
   11         char *p;
   12         int i;
   13 
   14 
   15         puts("before mmap...pls show free:.n");
   16         sleep(10);
✗  17         p = (char *)mmap(0, MAP_LEN, PROT_READ |PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   18 
   19         puts("after mmap....n");
   20 
   21         puts("before read...pls show free:.n");
   22         sleep(10);
   23 
   24         puts("start read....n");
   25 
   26 
   27         for(i=0;i <4096 *10; i++)
   28                 printf("%d ", p[4096 * i]);
   29         printf("n");
   30 
   31         puts("after read....pls show free:n");
   32 
   33         sleep(10);
   34 
   35         puts("start write....n");
   36 
   37         for(i=0;i <4096 *10; i++)
   38                 p[4096 * i] = 0x55;
   39 
   40 
   41         puts("after write...pls show free:.n");
   42 
   43         pause();
   44 
   45         return 0;
   46 }

执行结果:出现"before mmap ->please exec: free -m" 后执行:

$ free -m
              总计         已用        空闲      共享    缓冲/缓存    可用
内存:15921        6590         631         780        8700        8164
交换:16290         702       15588

出现"before read ->please exec: free -m"后执行:

$ free -m
              总计         已用        空闲      共享    缓冲/缓存    可用
内存:15921        6586         644         770        8690        8178
交换:16290         702       15588

出现"after read ->please exec: free -m"后执行:

$ free -m
              总计         已用        空闲      共享    缓冲/缓存    可用
内存:15921        6587         624         789        8709        8158
交换:16290         702       15588

出现"after write ->please exec: free -m"后执行:

$ free -m
              总计         已用        空闲      共享    缓冲/缓存    可用
内存:15921        6749         462         789        8709        7996
交换:16290         702       15588

可以发现:读之后和之前基本上内存使用没有变化(实际上映射到了0页,这是内核初始化时候分配好的),知道写之后6749-6587=162M符合预期,而且打印可以发现数据全为0。

分析:实际上,mmap的时候只是申请了一块vma,读的时候发生一次缺页异常,映射到0页,所有内存没有分配,当再次写这个页面的时候,发生了COW分配新页(cow中分配新页的时候会判断原来的页是否为0页,如果为0页就直接分配页然后用0填充)。

五,总结

匿名映射缺页异常是我们遇到的一种很常用的一种异常,对于匿名映射,映射完成之后,只是获得了一块虚拟内存,并没有分配物理内存,当第一次访问的时候:如果是读访问,会将虚拟页映射到0页,以减少不必要的内存分配;如果是写访问,则会分配新的物理页,并用0填充,然后映射到虚拟页上去。而如果是先读访问一页然后写访问这一页,则会发生两次缺页异常:第一次是匿名页缺页异常的读的处理,第二次是写时复制缺页异常处理。



Tags:Linux内核   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
什么是linux内核linux就像是一个哲学的最佳实践。如果非要对它评价,我真的不知道该怎么赞叹,我只能自豪地说着:“linux的美丽简直让人沉醉。”我只能说是我处在linux学习的修炼...【详细内容】
2021-12-23  Tags: Linux内核  点击:(15)  评论:(0)  加入收藏
内核空间 和用户空间申请的内存最终和buddy怎么交互?以及在页表映射上的区别?虚拟地址到物理地址,什么时候开始映射?Buddy的问题分配的力度太大 buddy算法把空闲页面分成1,2,4页,bu...【详细内容】
2021-12-07  Tags: Linux内核  点击:(25)  评论:(0)  加入收藏
1、设备树的概念在内核源码中,存在大量对板级细节信息描述的代码。这些代码充斥在/arch/arm/plat-xxx和/arch/arm/mach-xxx目录,对内核而言这些platform设备、resource、i2c_b...【详细内容】
2021-11-26  Tags: Linux内核  点击:(31)  评论:(0)  加入收藏
自旋锁:如果内核配置为SMP系统,自旋锁就按SMP系统上的要求来实现真正的自旋等待,但是对于UP系统,自旋锁仅做抢占和中断操作,没有实现真正的“自旋”。如果配置了CONFIG_DEBUG_SPI...【详细内容】
2021-10-21  Tags: Linux内核  点击:(37)  评论:(0)  加入收藏
1. Linux内核时钟系统和定时器实现Linux 2.6.16之前,内核只支持低精度时钟,内核定时器的工作方式: 系统启动后,会读取时钟源设备(RTC, HPET,PIT&hellip;),初始化当前系统时间; 内...【详细内容】
2021-09-29  Tags: Linux内核  点击:(50)  评论:(0)  加入收藏
1. 红黑树1.1 红黑树概述红黑树和我们以前学过的AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。不过自从红黑树出来后,AVL...【详细内容】
2021-06-24  Tags: Linux内核  点击:(119)  评论:(0)  加入收藏
UDP报文接收概述UDP数据报的接收要分两部分来看: 网络层接收完数据包后递交给UDP后,UDP的处理过程。该过程UDP需要做的工作就是接收数据包并对其进行校验,校验成功后将其放入接...【详细内容】
2021-06-04  Tags: Linux内核  点击:(93)  评论:(0)  加入收藏
题目是一个典型 《Effective C++》 的风格。事情是这样的,我大致说一下。我在开发一个Netfilter模块,在PREROUTING匹配一些数据包,显而易见,都能想到使用哈希表hlist作为数据结...【详细内容】
2021-05-18  Tags: Linux内核  点击:(200)  评论:(0)  加入收藏
需求在Linux SMP(对称多处理器)环境下,每个CPU对应一个run_queue(可执行队列)。如果一个进程处于TASK_RUNNING状态(可执行状态),则它会被加入到其中一个run_queue(且同一时刻仅会被加...【详细内容】
2021-04-01  Tags: Linux内核  点击:(225)  评论:(0)  加入收藏
Linux内核是GNU/Linux操作系统的核心组件。它是一个免费、开源、庞大、模块化、多任务的类Unix的操作系统内核。它最初是由Linus Torvalds在1991年为他的i386 PC创造的。实...【详细内容】
2021-03-18  Tags: Linux内核  点击:(274)  评论:(0)  加入收藏
▌简易百科推荐
作用显示文件或目录所占用的磁盘空间使用命令格式du [option] 文件/目录命令功能显示文件或目录所占用的磁盘空间一些写法的区别du -sh xxx 显示总目录的大小,但是不会列出...【详细内容】
2021-12-23  mitsuhide1992    Tags:du命令   点击:(12)  评论:(0)  加入收藏
什么是linux内核linux就像是一个哲学的最佳实践。如果非要对它评价,我真的不知道该怎么赞叹,我只能自豪地说着:“linux的美丽简直让人沉醉。”我只能说是我处在linux学习的修炼...【详细内容】
2021-12-23  linux上的码农    Tags:linux内核   点击:(15)  评论:(0)  加入收藏
本文将比较 Linux 中 service 和 systemctl 命令,先分别简单介绍这两个命令的基础用法,然后进行比较。从 CentOS 7.x 开始,CentOS 开始使用 systemd 服务来代替 service服务(dae...【详细内容】
2021-12-23  软件架构    Tags:systemctl   点击:(13)  评论:(0)  加入收藏
mv是move的缩写,可以用来移动文件或者重命名文件名,经常用来备份文件或者目录。命令格式mv [选项] 源文件或者目录 目标文件或者目录命令功能mv命令中第二个参数类型的不同(...【详细内容】
2021-12-17  入门小站    Tags:mv命令   点击:(23)  评论:(0)  加入收藏
大数据技术AI Flink/Spark/Hadoop/数仓,数据分析、面试,源码解读等干货学习资料 98篇原创内容 -->公众号 Linux sed 命令是利用脚本来处理文本文件。sed 可依照脚本的指令来处...【详细内容】
2021-12-17  仙风道骨的宝石骑士    Tags:sed命令   点击:(21)  评论:(0)  加入收藏
Node是个啥?  写个东西还是尽量面面俱到吧,所以有关基本概念的东西我也从网上选择性地拿了下来,有些地方针对自己的理解有所改动,对这些概念性的东西有过了解的可选择跳过这段...【详细内容】
2021-12-15  linux上的码农    Tags:node   点击:(21)  评论:(0)  加入收藏
难道只有我一个人觉得Ubuntu的unity桌面非常好用吗?最近把台式机上面的Ubuntu 16.04格式化了,装了黑苹果用了一周,不得不说,MacOS确实很精美,软件生态比Linux丰富很多,比Windows简...【详细内容】
2021-12-14  地球末日村    Tags:ubuntu   点击:(34)  评论:(0)  加入收藏
简介Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast Memberships) 等等。输出信息含义执行net...【详细内容】
2021-12-13  窥镜天    Tags:Linux netstat   点击:(26)  评论:(0)  加入收藏
对于较多数量的文件描述符的监听无论是select还是poll系统调用都显得捉襟见肘,poll每次都需要将所有的文件描述符复制到内核,内核本身不会对这些文件描述符加以保存,这样的设计...【详细内容】
2021-12-13  深度Linux    Tags:Linux   点击:(16)  评论:(0)  加入收藏
今天,我们来了解下 Linux 系统的革命性通用执行引擎-eBPF,之所以聊着玩意,因为它确实牛逼,作为一项底层技术,在现在的云原生生态领域中起着举足轻重的作用。截至目前,业界使用范...【详细内容】
2021-12-10  架构驿站    Tags:eBPF   点击:(24)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条