@@ -360,302 +360,6 @@ Need DMA-able memory, cannot sleep | Use `(GFP_DMA | GFP_ATOMIC)`, or perform yo
360
360
361
361
> **TLB (translation lookside buffer)** 是一种 **硬缓冲区**,很多体系结构用它来缓冲 **虚拟地址到物理地址的映射关系**。它极大地提高了系统性能,因为大多数内存都要进行虚拟寻址。
362
362
363
- # slab层(Slab Layer)
364
-
365
- * slab分配器扮演了 **通用数据结构缓存** 的角色。
366
- * slab分配器试图在几个基本原则之间寻求一种平衡:
367
- * 频繁使用的数据结构也会频繁分配和释放,因此应当缓存它们。
368
- * 频繁地分配和回收必然会导致内存碎片(难以找到大块连续可用的内存)。为了避免这种现象,空闲链表的缓存会连续地存放。因为已经释放的数据结构又会放回空闲链表,因此不会导致碎片。
369
- * 回收的对象可以立即投入下一次分配,因此,对于频繁的分配和释放,空闲链表能够提高其性能。
370
- * 如果分配器知道对象大小,页大小和总的高速缓存的大小这样的概念,它会作出更明智的决策。
371
- * 如果让部分缓存专属于单个处理器(对系统上的每个处理器独立而唯一),那么,分配和释放就可以在不加SMP锁的情况下运行。
372
- * 如果分配器是与NUMA相关的,它就可以从相同的内存结点为请求者进行分配。
373
- * 对存放的对象进行着色(color),以防止多个对象映射到相同的高速缓存行(cache line)。
374
-
375
- ## slab层的设计
376
- 
377
- * 不同对象划分为 **高速缓存组**,其中每个高速缓存组都存放 **不同类型** 的对象。**每种对象类型** 对应一个高速缓存。
378
- * `kmalloc()`接口建立在slab层之上,使用了一组通用高速缓存。
379
- * 高速缓存被划分为 **slab**,slab由一个或多个物理上连续的页组成。
380
- * 一般情况下,slab也就仅仅由一页组成。每个高速缓存可以由多个slab组成。
381
- * 每个slab都包含一些被缓存的数据结构。
382
- * 每个slab处于三种状态之一:满,部分满,空。
383
- * 当内核某一部分需要一个新对象时:
384
- * 先从 *部分满* 的slab中进行分配。
385
- * 没有 *部分满*,则从 *空* slab中进行分配。
386
- * 没有 *空* slab,则创建一个slab。
387
- * 注意 slabs_empty 列表中的 slab 是进行 **回收(reaping)** 的主要备选对象。正是通过此过程,slab 所使用的内存被返回给操作系统供其他用户使用。
388
- * slab 列表中的每个 slab 都是一个连续的内存块(一个或多个连续页),它们被划分成一个个对象。这些对象是从特定缓存中进行分配和释放的基本元素。
389
- * 注意 slab 是 slab 分配器进行操作的最小分配单位,因此如果需要对 slab 进行扩展,这也就是所扩展的最小值。
390
- * 由于对象是从 slab 中进行分配和释放的,因此单个 slab 可以在 slab 列表之间进行移动。
391
- * 例如,当一个 slab 中的所有对象都被使用完时,就从 slabs_partial 列表中移动到 slabs_full 列表中。
392
- * 当一个 slab 完全被分配并且有对象被释放后,就从 slabs_full 列表中移动到 slabs_partial 列表中。
393
- * 当所有对象都被释放之后,就从 slabs_partial 列表移动到 slabs_empty 列表中。
394
-
395
- ### slab 背后的动机
396
- 与传统的内存管理模式相比, slab 缓存分配器提供了很多优点。
397
- * 首先,内核通常依赖于对小对象的分配,它们会在系统生命周期内进行无数次分配。slab 缓存分配器通过对类似大小的对象进行缓存而提供这种功能,从而避免了常见的碎片问题。
398
- * slab 分配器还支持通用对象的初始化,从而避免了为同一目而对一个对象重复进行初始化。
399
- * 最后,slab 分配器还可以支持硬件缓存对齐和着色,这允许不同缓存中的对象占用相同的缓存行,从而提高缓存的利用率并获得更好的性能。
400
-
401
- #### 高速缓存结构 kmem_cache
402
- * 每个高速缓存都用`kmem_cache`结构表示。
403
- * include/linux/slab_def.h
404
- ```c
405
- /*
406
- * Definitions unique to the original Linux SLAB allocator.
407
- */
408
-
409
- struct kmem_cache {
410
- /*per-cpu数据,每次分配/释放期间都会访问*/
411
- struct array_cache __percpu *cpu_cache;
412
-
413
- /* 1) Cache tunables. Protected by slab_mutex */
414
- unsigned int batchcount;
415
- unsigned int limit;
416
- unsigned int shared;
417
-
418
- unsigned int size;
419
- struct reciprocal_value reciprocal_buffer_size;
420
- /* 2) touched by every alloc & free from the backend */
421
-
422
- unsigned int flags; /* constant flags */
423
- unsigned int num; /* # of objs per slab */
424
-
425
- /* 3) cache_grow/shrink */
426
- /* order of pgs per slab (2^n) */
427
- unsigned int gfporder;
428
-
429
- /* force GFP flags, e.g. GFP_DMA */
430
- gfp_t allocflags;
431
-
432
- size_t colour; /* cache colouring range */
433
- unsigned int colour_off; /* colour offset */
434
- struct kmem_cache *freelist_cache;
435
- unsigned int freelist_size;
436
-
437
- /* constructor func */
438
- void (*ctor)(void *obj);
439
-
440
- /* 4) cache creation/removal */
441
- const char *name;
442
- struct list_head list;
443
- int refcount;
444
- int object_size;
445
- int align;
446
-
447
- /* 5) statistics */
448
- ...
449
-
450
- struct kmem_cache_node *node[MAX_NUMNODES];
451
- };
452
- ...
453
- ```
454
-
455
- #### 三个 slab 链表和 Per-CPU 的 array_cache
456
-
457
- * mm/slab.h
458
- ``` c
459
- /*
460
- * struct array_cache
461
- *
462
- * Purpose:
463
- * - LIFO ordering, to hand out cache-warm objects from _alloc
464
- * - reduce the number of linked list operations
465
- * - reduce spinlock operations
466
- *
467
- * The limit is stored in the per-cpu structure to reduce the data cache
468
- * footprint.
469
- *
470
- */
471
- struct array_cache {
472
- unsigned int avail;
473
- unsigned int limit;
474
- unsigned int batchcount;
475
- unsigned int touched;
476
- void *entry[]; /*
477
- * Must have this definition in here for the proper
478
- * alignment of array_cache. Also simplifies accessing
479
- * the entries.
480
- */
481
- };
482
- ...
483
- /*
484
- * The slab lists for all objects.
485
- */
486
- struct kmem_cache_node {
487
- spinlock_t list_lock;
488
-
489
- #ifdef CONFIG_SLAB
490
- struct list_head slabs_partial; /* partial list first, better asm code */
491
- struct list_head slabs_full;
492
- struct list_head slabs_free;
493
- unsigned long free_objects;
494
- unsigned int free_limit;
495
- unsigned int colour_next; /* Per-node cache coloring */
496
- struct array_cache *shared; /* shared per node */
497
- struct alien_cache **alien; /* on other nodes */
498
- unsigned long next_reap; /* updated without locking */
499
- int free_touched; /* updated without locking */
500
- #endif
501
-
502
- #ifdef CONFIG_SLUB
503
- unsigned long nr_partial;
504
- struct list_head partial;
505
- #ifdef CONFIG_SLUB_DEBUG
506
- atomic_long_t nr_slabs;
507
- atomic_long_t total_objects;
508
- struct list_head full;
509
- #endif
510
- #endif
511
-
512
- };
513
- ```
514
-
515
- * ` kmem_getpages() ` 创建新的slab。
516
- * ` kmem_getpages() ` 和` alloc_pages() ` 都会调用` __alloc_pages_nodemask() ` 来分配页。
517
- * ` kmem_freepages() ` 释放内存。
518
- * slab层只有当给定高速缓存部分中即 ** 没有满** 也 ** 没有空** 的slab的时才会调用页分配函数。
519
- * 只有在下列情况下才会调用 * 释放函数* :
520
- * 当可用内存变得紧缺时,系统试图释放出更多的内存以供使用;
521
- * 当高速缓存显示撤销时。
522
- * slab层的管理是在每个高速缓存的基础上,通过提供给整个系统一个简单的接口来完成的。通过接口就可以:
523
- * 创建和撤销新的高速缓存。
524
- * 在高速缓存内分配和释放对象。
525
- * 创建一个高速缓存后,slab层所起的作用就像一个专用的分配器,可以为具体的对象类型进行分配。
526
-
527
- #### __ SetPageSlab()宏
528
- * include/linux/page-flags.h
529
- ``` c
530
- enum pageflags {
531
- PG_locked, /* Page is locked. Don't touch. * /
532
- PG_error,
533
- PG_referenced,
534
- PG_uptodate,
535
- PG_dirty,
536
- PG_lru,
537
- PG_active,
538
- PG_slab,
539
- ...
540
- };
541
- ...
542
- static inline struct page *compound_head (struct page * page)
543
- {
544
- unsigned long head = READ_ONCE(page->compound_head);
545
-
546
- if (unlikely(head & 1))
547
- return (struct page *) (head - 1);
548
- return page;
549
- }
550
-
551
- static __ always_inline int PageTail(struct page * page)
552
- {
553
- return READ_ONCE(page->compound_head) & 1;
554
- }
555
- ...
556
- /*
557
- * Page flags policies wrt compound pages
558
- *
559
- * PF_ANY:
560
- * the page flag is relevant for small, head and tail pages.
561
- *
562
- * PF_HEAD:
563
- * for compound page all operations related to the page flag applied to
564
- * head page.
565
- *
566
- * PF_NO_TAIL:
567
- * modifications of the page flag must be done on small or head pages,
568
- * checks can be done on tail pages too.
569
- *
570
- * PF_NO_COMPOUND:
571
- * the page flag is not relevant for compound pages.
572
- * /
573
- #define PF_ANY(page, enforce) page
574
- #define PF_HEAD(page, enforce) compound_head(page)
575
- #define PF_NO_TAIL(page, enforce) ({ \
576
- VM_BUG_ON_PGFLAGS(enforce && PageTail(page), page); \
577
- compound_head(page);})
578
- #define PF_NO_COMPOUND(page, enforce) ({ \
579
- VM_BUG_ON_PGFLAGS(enforce && PageCompound(page), page); \
580
- page;})
581
-
582
- /*
583
- * Macros to create function definitions for page flags
584
- * /
585
- #define TESTPAGEFLAG(uname, lname, policy) \
586
- static __ always_inline int Page##uname(struct page * page) \
587
- { return test_bit(PG_ ##lname, &policy(page, 0)->flags); }
588
- ...
589
- #define __ SETPAGEFLAG(uname, lname, policy) \
590
- static __ always_inline void __ SetPage##uname(struct page * page) \
591
- { __ set_bit(PG_ ##lname, &policy(page, 1)->flags); }
592
-
593
- #define __ CLEARPAGEFLAG(uname, lname, policy) \
594
- static __ always_inline void __ ClearPage##uname(struct page * page) \
595
- { __ clear_bit(PG_ ##lname, &policy(page, 1)->flags); }
596
- ...
597
- #define __ PAGEFLAG(uname, lname, policy) \
598
- TESTPAGEFLAG(uname, lname, policy) \
599
- __ SETPAGEFLAG(uname, lname, policy) \
600
- __ CLEARPAGEFLAG(uname, lname, policy)
601
-
602
- ...
603
- __ PAGEFLAG(Slab, slab, PF_NO_TAIL)
604
- ```
605
- * 宏展开后的函数定义
606
- ```c
607
- /*__ arch/x86/include/asm/bitops.h*/
608
- /**
609
- * __set_bit - Set a bit in memory
610
- * @nr: the bit to set
611
- * @addr: the address to start counting from
612
- *
613
- * Unlike set_bit(), this function is non-atomic and may be reordered.
614
- * If it's called on the same region of memory simultaneously, the effect
615
- * may be that only one operation succeeds.
616
- */
617
- static __always_inline void __set_bit(long nr, volatile unsigned long *addr)
618
- {
619
- asm volatile("bts %1,%0" : ADDR : "Ir" (nr) : "memory");
620
- }
621
-
622
- static __always_inline void __SetPageSlab(struct page *page)
623
- { __set_bit(PG_slab, &({
624
- do {
625
- if (unlikely(1 && PageTail(page))) {
626
- dump_page(page, "VM_BUG_ON_PAGE(" __stringify(1 && PageTail(page))")");
627
- BUG();
628
- }
629
- } while (0);
630
- compound_head(page);})->flags); }
631
- ```
632
-
633
- ## slab分配器的接口
634
-
635
- * ` kmem_cache_create() ` 创建一个新的高速缓存。
636
- * ` SLAB_HWCACHE_LINE ` slab层把一个slab内的所有对象和硬件cache line对齐。可以提高性能,但增加了内存开销,空间换时间。
637
- * ` SLAB_POISON ` 内存毒化标志,用已知的值填充slab。
638
- * ` SLAB_RED_ZONE ` 在已分配的内存周围插入“红色警界区”以探测缓冲越界。
639
- * ` SLAB_PANIC ` 分配失败时提醒slab层。这在要求分配只能成功的时候非常有用。
640
- * ` SLAB_CACHE_DMA ` 命令slab层用 * 可以执行DMA的内存* 给每个slab分配空间。
641
- * 只在 * 分配的对象用于DMA* ,且 * 必须驻留在` ZONE_DMA ` 区`时* 才需要这个标志。
642
- * 否则不需要,也不应该设置。
643
- * ** 不能用于中断上下文** ,会睡眠。
644
- * ` kmem_cache_destory() ` 撤销给定的高速缓存。
645
- * ** 不能用于中断上下文** ,会睡眠。
646
- * 除此之外还需确保:
647
- * 高速缓存中所有的slab都必须为空。
648
- * 在调用` kmem_cache_destory() ` 过程中(更别提之后了)不再访问这个高速缓存。调用者必须确保同步。
649
- * ` kmem_cache_alloc() ` 从给定的高速缓存中分配对象。
650
- * 如果高速缓存中所有的slab中都没有空闲对象,slab层必须通过` kmem_getpages() ` 获取新的页。
651
- * ` kmem_cache_free() ` 释放一个对象,并返还给原先的slab。
652
- * slab层负责内存紧缺情况下所有底层的对齐,着色,分配,释放,回收等。
653
- * 如果要频繁创建很多相同类型的对象,应该考虑使用slab高速缓存,而不是自己实现空闲链表。
654
-
655
- ## 查看slab信息
656
- * [ ` cat /proc/slabinfo ` ] ( http://man7.org/linux/man-pages/man5/slabinfo.5.html )
657
- * [ ` slbtop ` ] ( http://man7.org/linux/man-pages/man1/slabtop.1.html )
658
-
659
363
# 栈上的静态分配
660
364
* 每个进程的 **内核栈** 大小即依赖 *体系结构*,也与 *编译选项* 有关。
661
365
* 历史上,每个进程都有 **两页** 的内核栈。
@@ -822,9 +526,8 @@ static inline void __kunmap_atomic(void *addr)
822
526
* 注意:**不能在访问 Per-CPU 数据过程中睡眠**,否则,醒来可能在其他CPU上。
823
527
* Per-CPU 的新接口并不兼容之前的内核。
824
528
825
-
826
529
# 参考资料
827
- * https://www.ibm.com/developerworks/cn/linux/l-linux-slab-allocator/
530
+ * [Linux slab 分配器剖析]( https://www.ibm.com/developerworks/cn/linux/l-linux-slab-allocator/)
828
531
* [/PROC/MEMINFO之谜](http://linuxperf.com/?p=142)
829
532
* [怎样诊断SLAB泄露问题](http://linuxperf.com/?p=148)
830
533
* [Linux内核高端内存](http://ilinuxkernel.com/?p=1013)
0 commit comments