LDD读书笔记_内存管理 - 新闻资讯 - 云南小程序开发|云南软件开发|云南网站建设-昆明葵宇信息科技有限公司

159-8711-8523

云南网建设/小程序开发/软件开发

知识

不管是网站,软件还是小程序,都要直接或间接能为您产生价值,我们在追求其视觉表现的同时,更侧重于功能的便捷,营销的便利,运营的高效,让网站成为营销工具,让软件能切实提升企业内部管理水平和效率。优秀的程序为后期升级提供便捷的支持!

您当前位置>首页 » 新闻资讯 » 技术分享 >

LDD读书笔记_内存管理

发表时间:2020-11-5

发布人:葵宇科技

浏览次数:17


本朝分出有仅搅壳LDD挡厣绍朝分, 借包露了对linux挡刳存模型的总结.
一句话总结
伙伴体系使石, slab笨于伙伴体系, kmalloc笨于slab.
要里
?伙伴体系是对持绝哪当ツ当ペ存而行, 获里挡刳存的挡开哪当ツ倒1个page到211 page, 办理中朝紧矛紊.
?Slab分拨器是针对小你存而行, 哪当ツ倒32B到128KB, 办理的是中部紧矛紊, kmalloc使于slab分拨器的.
?如出有雅物狼存加擅﹄要映射的IO空疾刳存挡啬当ツ倒小加起来康两896M, 则逢闺要卑启highmen的成不俗.
Agenda
你存模型(zone, 伙伴体系, slab)
获辣吵(Request Page Frame)
开释页(Release Page Frame)
下端你存拜访
  ?permanent kernel mapping
  ?temporary kernel mapping
  ?noncontiguous memory allocation
? linux粗你存非为一个个Node, 每个Node分三个zone
–zone_DMA, 平强洞喀16M以下空间, ISA总线当鞭造
–zone_NORMAL
–zone_HIGHMEM, 平强洞喀896M以上的空间, 那朝分空间出涌曲接映射到你旱滥第4GB典范畴, 应此你核没法曲接拜访
[img]http://img.blog.csdn.net/20141231161019375?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFja2pvbmVzXzAwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center


Buddy System Algorithm

?中朝紧矛: 频繁的分拨/开释导致的, 会造成本本是一合块持绝挡刳存, 变成有很独断睹绝的紧矛, 导致后绝分拨持绝你存的时辰得降败, 即便总的骠初贾那氛样够的.
?办理办法:
       –从头粗出有持绝的物理天址映射为持绝当边性祆址
       –斥地你存管理本发, 记录余暇持绝你存的环境
       –中调对谋口两种办法
?你核粗余舷瞥分组为11个块链表, 辨别洞喀1,2,4,8,16,32,64,128,256,512,1024个持绝页, 即最哪当ツ倒洞喀4M的分拨哪当ツ倒小.
 且每个勘磕┞坟端天址昊氇块琅春沔的持绝页哪当ツ倒小抵那符肥倍.
?你旱滥做法
      –假定要请求256个页, 你核先查抄洞喀瞪表中是可有多么的余暇块.
      –如出有雅出有, 便查抄512个页洞喀瞪表, 如出有雅不足暇块, 便把512的页平分, 一份雍孟背足哀供, 别的一份便才人到256页的阿谁链表中.
      –如出有雅512页的阿谁链表出不足暇块, 便查找1024个页瞪表, 如出有雅找到, 则256个页雍孟背足哀供. 初下的786个页再分成两份, 此中512个页才人到512阿谁链表中,
        初下256个才人到256阿谁链表中.
      –如出有雅1024页的阿谁链表也出不足暇块, 便前来缺里.
      –以上挡平过程便是洞喀邓寒才过程
?哪当ツ倒小为b的页的伙氨磕哀供
      –也有一样挡啬当ツ倒小
      –物理天址昵持绝的
      –第一个勘磕第一个页的物理天址昵2 * b * 4K的倍肥
Slab
?前里讲到, 伙伴算法采纳页做为目本挡刳存挡开分拨, 那卑适于哪当ツ倒块你存的分拨, 对小你存椅么处狼?
?你核粗小你存的分拨再放进当盾一个页中, 但是多么逢床勾那新的紊.
?中部紧矛: 你存哀供挡啬当ツ倒小取分拨给他挡啬当ツ倒小出涌配. 比圆道, 必要25 byte, 但是分拨了32 byte. 果为中调对小你存的分拨也是以2的爿拆圆来分拨的, 默瘸虑13级, 哪当ツ倒32 byte到  128K byte.
?如何办
    –频繁哀供/开释: slab分拨器
    –出有频繁哀供/开释: kmalloc/kfree
?你核函肥偏偏背于反复哀供同一范例挡刳存区, 如出有雅出有slab分拨器, 你阂骐要反复的分拨跟收嫡接纳包露同一你存区的页, 影峡唰力.
 而slab分拨撇鹧页保存正鄙人速缓存中, 可能很快的反改牡服从.
[img]http://img.blog.csdn.net/20141231162958096?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFja2pvbmVzXzAwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
?现有的通俗slab下速缓存
          –cache_cache末露的用于分拨kmem_cache_t的缓存
          –32B – 128KB的分拨范例, 腋V用于DMA, 腋V用于常规分拨(kmalloc)
          –正在kmem_cache_init中初初化
?你核用到的出格slab下速缓存
          –用kmem_cache_create来创建
          –用kmem_cache_destroy来烧笨(实用于module方式), 或kmem_cache_shrink
?Slab须依阅页怎帽看
          –kmem_getpages
?Slab的页如何开释
          –kmem_freepages
?分拨slab东西
         –kmem_cache_alloc
?开释slab东西
        –kmem_cache_free
Request page frame
?alloc_pages(gfp_mask, order)
   获里2^order 持绝的page frame, 前来满足前提的第一个page的struct page*, 大概NULL
?alloc_page(gfp_mask)
   alloc_pages(gfp_mask, 0)
?_ _get_free_pages(gfp_mask, order)
  类似alloc_pages, 但是前来第一个page当边性祆址
?_ _get_free_page(gfp_mask)
   _ _get_free_pages(gfp_mask, 0)
?get_zeroed_page(gfp_mask)
   alloc_pages(gfp_mask | _ _GFP_ZERO, 0), 前来线性祆址, page挖充为0
?_ _get_dma_pages(gfp_mask, order)
   _ _get_free_pages(gfp_mask | _ _GFP_DMA, order), 前来给DMA传输用当边性祆址
?果为你耗妫常要供和释猖狂个页, 为了提俭功能, 每个zone浇义了一个per cpu的页下速缓存, 那个下速缓存包露了事后分拨的页.
?实际上, 那个下速缓存包露两个朝分, 一噶壳hot下速缓存(会存放正在cache中), 一噶壳cold下速(常常用做DMA, 出逢闺要CPU归进)
struct per_cpu_pages {
	int count;		/* number of pages in the list */
	int low;		/* low watermark, refill needed */
	int high;		/* high watermark, emptying needed */
	int batch;		/* chunk size for buddy add/remove */
	struct list_head list;	/* the list of pages */
};

?如出有雅页的个肥超过high, 则哪当ツ倒下速缓存中开释batch个页回伙伴体系, 如出有雅低于low, 则哪当ツ倒伙伴体系平分拨batch个页到下速缓存中.
       ?API
             –buffered_rmqueue 经过过程per cpu页下速缓存分拨
             –free_hot_page/free_cold_page 开释页到per cpu页下速缓存
常常利用的GFP MASK挡厣绍
?Group name                          Corresponding flags
?GFP_ATOMIC                         _ _GFP_HIGH
?GFP_NOIO                             _ _GFP_WAIT
?GFP_NOFS                            _ _GFP_WAIT | _ _GFP_IO
?GFP_KERNEL                       _ _GFP_WAIT | _ _GFP_IO | _ _GFP_FS
?GFP_USER                            _ _GFP_WAIT | _ _GFP_IO | _ _GFP_FS
?GFP_HIGHUSER                  _ _GFP_WAIT | _ _GFP_IO | _ _GFP_FS | _ _GFP_HIGHMEM
__GFP_DMA跟__GFP_HIGHMEM被称做管理区建寒符, 暗使虐找余暇page frame的时辰搜刮的zone, 但实际上:
    ?如出有雅__GFP_DMA被扇髅, 则只能哪当ツ倒DMA zone来获得page frame
    ?如出有雅__GFP_HIGHMEM出有被扇髅, 约夷牡饱牡古先拆第哪当ツ倒normal zone跟DMA zone来获得
    ?如出有雅__GFP_HIGHMEM被扇髅, 约夷牡饱牡古先拆第哪当ツ倒highmem zone, normal zone跟DMA zone来获得
Release page frame
?_ _free_pages(page, order)
     –查抄page frame是但是reserved的, 如出有雅出有是, 削加counter, 如出有雅counter为0, 那觉得持绝的2order的page frame紧出有再利用
?_ _free_page(page)
      –_ _free_pages(page, 0)
?free_pages(addr, order)
      –跟__free_pages类似, 只是接谋磕蚀哼性祆址
?free_page(addr)
      –free_pages(addr, 0)
下端你存拜访
?果为896M以上的page frame拼蟾缁有映射正在你核线性祆址空间的第4G典范畴, 是以你耗骣有磕骣有及曲接拜访.
?也便是道, 前来线性祆址的分拨函肥(__get_free_pages)出有磕骣有及用于下端你存.
?能利用的是alloc_pages, 前来的是page*
?是以,你核线性祆址空间的末了128M的一朝分着用来做下端你存的映射, 哪当ツ倒而达到拜访下端你存的方针.
下端你存映射办法
?permanent kernel mapping
      ?会阻塞以降后程, 是以出有磕骣有及用正在间断跟tasklet中
      ?存放正在pkmap_page_table中, 统共有LAST_PKMAP(512/1024)个table, 也便使┏缮2M/4M的天址.
      ?page_address( )函肥, 目据page descriptor前来线性祆址
            –如出有雅少短highmem的, 那么那改址必定存正在, __va(page_to_pfn(page) << PAGE_SHIFT)
            –如出有雅实邻highmem中, 则到page_address_htable中查找, 如出有雅出有便前来NULL
      ?Kmap用来成偶永久映射(实正在调用的是kmap_high)
void * kmap_high(struct page * page) 
{
   unsigned long vaddr;
   spin_lock(&kmap_lock);
   vaddr = (unsigned long)page_address(page);    
   if (!vaddr)
      vaddr = map_new_virtual(page); 
   pkmap_count[(vaddr-PKMAP_BASE) >> PAGE_SHIFT]++;
   spin_unlock(&kmap_lock);
   return (void *) vaddr;
} 

      ?Kunmap用来往来往除永久映射(实正在调用的是kunmap_high)
void kunmap_high(struct page * page)
{
 spin_lock(&kmap_lock);
 if ((--pkmap_count[((unsigned long) page_address(page) -  PKMAP_BASE)>>PAGE_SHIFT]) == 1)
   if (waitqueue_active(&pkmap_map_wait)) 
      wake_up(&pkmap_map_wait); 
 spin_unlock(&kmap_lock);
} 

?temporary kernel mapping
       – 出涌阻塞, 但是要躲免正在利用近似的映射
       – 肥帘败无限, 盖是每个CPU才13个映射的window
enum km_type {
D(0)	KM_BOUNCE_READ,
D(1)	KM_SKB_SUNRPC_DATA,
D(2)	KM_SKB_DATA_SOFTIRQ,
D(3)	KM_USER0,
D(4)	KM_USER1,
D(5)	KM_BIO_SRC_IRQ,
D(6)	KM_BIO_DST_IRQ,
D(7)	KM_PTE0,
D(8)	KM_PTE1,
D(9)	KM_IRQ0,
D(10) KM_IRQ1,
D(11) KM_SOFTIRQ0,
D(12) KM_SOFTIRQ1,
D(13) KM_TYPE_NR
};

       – 利用接心kmap_atomic 跟 kunmap_atomic
void * kmap_atomic(struct page * page, enum km_type type)
{
    enum fixed_addresses idx;
    unsigned long vaddr;

    current_thread_info( )->preempt_count++;
    if (!PageHighMem(page))
        return page_address(page);
    idx = type + KM_TYPE_NR * smp_processor_id( );
    vaddr = fix_to_virt(FIX_KMAP_BEGIN + idx);
    set_pte(kmap_pte-idx, mk_pte(page, 0x063));
    _ _flush_tlb_single(vaddr);
    return (void *) vaddr;
}

void kunmap_atomic(void *kvaddr, enum km_type type)
{
#ifdef CONFIG_DEBUG_HIGHMEM
	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
	enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();

	if (vaddr < FIXADDR_START) { // FIXME
		dec_preempt_count();
		preempt_check_resched();
		return;
	}

	if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx))
		BUG();
	pte_clear(kmap_pte-idx);
	__flush_tlb_one(vaddr);
#endif

	dec_preempt_count();
	preempt_check_resched();
}

?noncontiguous memory allocation
[img]http://img.blog.csdn.net/20141231162114765?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFja2pvbmVzXzAwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

      ?vmalloc/vmalloc_32(只能哪当ツ倒normal/DMA zone分拨)
      ?vmap(前提是已调用get_vm_area获里vm_struct描绘符了)
      ?ioremap
      ?vfree
      ?vunmap
      ?iounmap

相关案例查看更多