深入linux內(nèi)核架構(gòu)--內(nèi)存管理(簡介)

前言

??內(nèi)存管理其實是一個很基本的概念财忽,但是真正能把linux內(nèi)存管理梳理清楚的人很少,也看過網(wǎng)上很多關(guān)于內(nèi)存管理的文章泣侮,但是總感覺他們其實也是照搬的一些概念即彪,都不是很系統(tǒng),看起來冰山一角活尊,似懂非懂隶校。那么今天就系統(tǒng)的結(jié)合linux源碼來記錄一下內(nèi)存管理,希望能形成一套完整體系蛹锰,對Linux內(nèi)存有一個完整的了解深胳。(文章后續(xù)的很多內(nèi)存數(shù)字舉例都是基于4GB物理內(nèi)存大小的系統(tǒng))。
??關(guān)于內(nèi)存管理一定要區(qū)分兩個概念宁仔,內(nèi)核空間內(nèi)存管理及用戶空間內(nèi)存管理稠屠,Linux在這兩個空間的內(nèi)存管理方式非常不同,但也有一些相同點:1. 都有頁表翎苫;2. 都是通過虛擬地址訪問內(nèi)存权埠。主要的不同點:1. 內(nèi)核中虛擬地址到物理地址基本是直接映射,分配連續(xù)的物理內(nèi)存(也可以分配非連續(xù)的內(nèi)存煎谍,比如vmalloc等攘蔽,具體后續(xù)單獨描述),而用戶空間會基于進(jìn)程各自的頁表呐粘,分配非連續(xù)的物理內(nèi)存满俗;2. 物理內(nèi)存中有一部分內(nèi)存只能被內(nèi)核訪問的(具體見內(nèi)核域劃分)。所以內(nèi)核空間會直接依賴物理內(nèi)存的管理作岖,而用戶空間則需要多一層的虛擬地址空間到物理地址的轉(zhuǎn)換唆垃。
??linux內(nèi)核一般將虛擬地址空間劃分為會兩部分,將底部比較大的部分用于用戶進(jìn)程痘儡,頂部專用于內(nèi)核進(jìn)程辕万,在IA-32系統(tǒng)上比例為3:1,因此內(nèi)核訪問的地址一般是從0xC0000000開始沉删。內(nèi)核空間的內(nèi)存管理相對要簡單一些渐尿,因為內(nèi)核空間信任自身,而沒法信任用戶程序矾瑰。內(nèi)核對于物理內(nèi)存管理主要包括以下幾個概念:分配大塊內(nèi)存的伙伴系統(tǒng)砖茸;分配非連續(xù)內(nèi)存塊的vmalloc機(jī)制及內(nèi)存映射機(jī)制;分配小塊內(nèi)存的slab,slub和slob殴穴;該節(jié)主要講的是內(nèi)核物理內(nèi)存的體系結(jié)構(gòu)凉夯,對于伙伴系統(tǒng)货葬,非連續(xù)內(nèi)存分配及slab則會用單獨的章節(jié)分析。

內(nèi)存體系結(jié)構(gòu)

1. UMA VS NUMA

有兩種類型的計算機(jī)劲够,分別以不同的方式管理物理內(nèi)存:
1)UMA(uniform memory access)計算機(jī)宝惰,將內(nèi)存以連續(xù)的方式組織起來。SMP系統(tǒng)中每個處理器都是訪問同一塊內(nèi)存再沧。
2)NUMA(non-uniform memory access)計算機(jī),總是多處理器計算機(jī)尊残,系統(tǒng)各個CPU有各自本地的內(nèi)存訪問炒瘸,各個處理器之間的總線是連著的,可以訪問其他CPU寝衫,但是要慢一些顷扩。
關(guān)于 UMA及NUMA的細(xì)節(jié)見 https://techdifferences.com/difference-between-uma-and-numa.html,簡而言之慰毅,就是 UMA總線邏輯更簡單隘截,但是訪問速度要慢,帶寬低汹胃;NUMA總線邏輯更復(fù)雜婶芭,但是訪問更高效,帶寬高着饥,也更容易伸縮犀农。UMA更適合分時系統(tǒng),NUMA更適合實時系統(tǒng)宰掉,UMA并行能力特別差呵哨。下面我們講解的主要是NUMA系統(tǒng),因為弄懂了NUMA系統(tǒng)的內(nèi)存管理轨奄,UMA就特別容易理解了孟害。

2. 內(nèi)核空間-內(nèi)存組織

  1. 內(nèi)存劃分為節(jié)點(pg_data_t),每個節(jié)點關(guān)聯(lián)到系統(tǒng)中的一個處理器挪拟。
  2. 每個節(jié)點有劃分成內(nèi)存域(zone)挨务,目前內(nèi)存域分為四種:(三個內(nèi)核內(nèi)存域,一個用戶內(nèi)存域)ZONE_DMA/ZONE_DMA32舞丛,ZONE_NORMAL耘子,ZONE_HIGHMEM。通過劃分內(nèi)存域可以更好的管理球切,針對不同的場景進(jìn)行更好的優(yōu)化谷誓。
    · ZONE_DMA標(biāo)記適合DMA的內(nèi)存域,在IA-32計算機(jī)上吨凑,一般的現(xiàn)在是16MB捍歪,該區(qū)域供I/O設(shè)備直接訪問户辱,不需要通過MMU管理,連續(xù)分配糙臼,具有更高的性能庐镐。
    · ZONE_DMA32,標(biāo)記了使用32位地址可尋址变逃、適合DMA的內(nèi)存域必逆,顯然只有64位系統(tǒng)上,才會有該內(nèi)存域揽乱。
    · ZONE_NORMAL名眉,可以直接映射到內(nèi)核段的普通內(nèi)存域,這是所有體系機(jī)構(gòu)上保證都會存在的唯一內(nèi)存域凰棉,在IA-32系統(tǒng)上损拢,該域可訪問的最大內(nèi)存不超過896MiB,超過該值的內(nèi)存只能能通過高端內(nèi)存尋址訪問ZONE_HIGHMEM中的內(nèi)存撒犀。
    · ZONE_HIGHMEM福压,超出了內(nèi)核段的物理內(nèi)存。只有在可用物理內(nèi)存多余可映射的內(nèi)核內(nèi)存時或舞,才會訪問該域荆姆,顯然一般只有32位系統(tǒng)上才會有可能有該區(qū)域。通過kmap及kunmap將該域內(nèi)存映射到內(nèi)核虛擬地址空間映凳。
    · ZONE_MOVEABLE胞枕,這個區(qū)域主要是給用戶空間分配使用。
    前三個zone主要為內(nèi)核所用到魏宽,最后一個主要被用戶空間用到腐泻,內(nèi)核空間內(nèi)存域具體劃分見下圖:
    內(nèi)核空間內(nèi)存域zone劃分

    由于內(nèi)核核心不依賴于高端內(nèi)存,所以一般優(yōu)先分配高端內(nèi)存队询,高端內(nèi)存分配完畢后才會分配普通內(nèi)存派桩。
    內(nèi)存組織結(jié)構(gòu)見下圖:
    NUMA系統(tǒng)中的內(nèi)存劃分

    數(shù)據(jù)結(jié)構(gòu)如下:
enum zone_type {
#ifdef CONFIG_ZONE_DMA
    ZONE_DMA,
#endif
#ifdef CONFIG_ZONE_DMA32
    ZONE_DMA32,
#endif
    ZONE_NORMAL,
#ifdef CONFIG_HIGHMEM
    ZONE_HIGHMEM,
#endif
    ZONE_MOVABLE,
#ifdef CONFIG_ZONE_DEVICE
    ZONE_DEVICE,
#endif
    __MAX_NR_ZONES
};
typedef struct pglist_data {
    struct zone node_zones[MAX_NR_ZONES]; /*內(nèi)存域*/
    struct zonelist node_zonelists[MAX_ZONELISTS]; /* 備域(NUMA備用節(jié)點) */
    int nr_zones; /* 內(nèi)存域數(shù)目 */
#ifdef CONFIG_FLAT_NODE_MEM_MAP /* means !SPARSEMEM */
    struct page *node_mem_map;  /* 所有內(nèi)存域中的頁 */
#ifdef CONFIG_PAGE_EXTENSION
    struct page_ext *node_page_ext; /* 內(nèi)存頁的更多描述信息*/
#endif
#endif
    unsigned long node_start_pfn; /* 節(jié)點起始頁幀編號(系統(tǒng)中的所有節(jié)點的頁幀編號唯一) */
    unsigned long node_present_pages; /* total number of physical pages */
    unsigned long node_spanned_pages; /* total size of physical page
                         range, including holes */
    int node_id;
    wait_queue_head_t kswapd_wait; /* kswapd的等待隊列*/
    wait_queue_head_t pfmemalloc_wait;
    struct task_struct *kswapd; /* Protected by
                       mem_hotplug_begin/end() */
    int kswapd_order;
    enum zone_type kswapd_classzone_idx;

    int kswapd_failures;        /* Number of 'reclaimed == 0' runs */
...
} pg_data_t;

struct zone {
    /* zone watermarks, access with *_wmark_pages(zone) macros */
    unsigned long _watermark[NR_WMARK]; /* min, low, high,不同內(nèi)存水位代表內(nèi)存有不同的壓力,后續(xù)會詳細(xì)介紹kswapd*/
    unsigned long watermark_boost;
    unsigned long nr_reserved_highatomic;
    long lowmem_reserve[MAX_NR_ZONES]; /* 指定數(shù)量的內(nèi)存頁蚌斩,用于無論如何都不能失敗的關(guān)鍵性內(nèi)存分配铆惑,不同的域有不同的計算方式*/
#ifdef CONFIG_NUMA
    int node; /* 代表第n個節(jié)點*/
#endif
    struct pglist_data  *zone_pgdat; /* 所在的節(jié)點 */
    struct per_cpu_pageset __percpu *pageset; /* 熱/冷頁幀列表,詳情見下面的描述及slab分配器 */
#ifndef CONFIG_SPARSEMEM
    ... /* 高級新特性送膳,后續(xù)研究完了再補一下*/
#endif
        ...
#ifdef CONFIG_MEMORY_ISOLATION
    ... /* 高級新特性员魏,后續(xù)研究完了再補一下*/
#endif
#ifdef CONFIG_MEMORY_HOTPLUG
    ... /* 高級新特性,后續(xù)研究完了再補一下*/
#endif
    int initialized;
    /* Write-intensive fields used from the page allocator */
    ZONE_PADDING(_pad1_) /* CPU高速緩存行叠聋,緩存填充撕阎,確保自旋鎖處于自身的緩存行中*/
    /* free areas of different sizes */
    struct free_area    free_area[MAX_ORDER]; /* 伙伴系統(tǒng),負(fù)責(zé)實際頁幀的分配 */
    /* zone flags, see below */
    unsigned long       flags;
    /* Primarily protects free_area */
    spinlock_t      lock;
    /* Write-intensive fields used by compaction and vmstats. */
    ZONE_PADDING(_pad2_)
    unsigned long percpu_drift_mark;
        ...
    ZONE_PADDING(_pad3_)
    /* Zone statistics */
    atomic_long_t       vm_stat[NR_VM_ZONE_STAT_ITEMS];
    atomic_long_t       vm_numa_stat[NR_VM_NUMA_STAT_ITEMS];
} ____cacheline_internodealigned_in_smp /*最優(yōu)高速緩存行對齊*/;

2.1 冷熱頁

冷熱頁主要是針對于CPU緩存的碌补,熱頁就是已經(jīng)加載入CPU緩存虏束,相反冷頁則說明頁不在CPU高速緩存中棉饶,關(guān)于CPU高速緩存將在slab內(nèi)存管理中統(tǒng)一描述。

struct per_cpu_pageset {
    struct per_cpu_pages pcp;
        ...
};
struct per_cpu_pages {
    int count;  /* number of pages in the list */
    int high;       /* high watermark, emptying needed */
    int batch;  /* chunk size for buddy add/remove */
    /* Lists of pages, one per migrate type stored on the pcp-lists */
    struct list_head lists[MIGRATE_PCPTYPES];
};

2.2 頁幀

??頁幀代表系統(tǒng)物理內(nèi)存映射的最小單位镇匀,對應(yīng)于struct page照藻,IA-32系統(tǒng)中標(biāo)準(zhǔn)頁的長度為4KiB。頁幀被伙伴系統(tǒng)管理著汗侵,所以當(dāng)一個或多個page被分配出來時幸缕,由伙伴系統(tǒng)管理page對應(yīng)的元信息,page中的數(shù)據(jù)可能是匿名映射首頁晰韵、slab緩存首頁冀值、伙伴頁或者頁表頁。
具體數(shù)據(jù)結(jié)構(gòu)如下:

struct page {
    unsigned long flags;        /* Atomic flags, some possibly
                     * updated asynchronously */
    /*
     * Five words (20/40 bytes) are available in this union.
     * WARNING: bit 0 of the first word is used for PageTail(). That
     * means the other users of this union MUST NOT use the bit to
     * avoid collision and false-positive PageTail().
     */
    union {
        struct {    /* Page cache and anonymous pages */
            /**
             * @lru: Pageout list, eg. active_list protected by
             * zone_lru_lock.  Sometimes used as a generic list
             * by the page owner.
             */
            struct list_head lru;
            /* See page-flags.h for PAGE_MAPPING_FLAGS */
            struct address_space *mapping;
            pgoff_t index;      /* Our offset within mapping. */
            /**
             * @private: Mapping-private opaque data.
             * Usually used for buffer_heads if PagePrivate.
             * Used for swp_entry_t if PageSwapCache.
             * Indicates order in the buddy system if PageBuddy.
             */
            unsigned long private;
        };
        struct {    /* slab, slob and slub */
            union {
                struct list_head slab_list; /* uses lru */
                struct {    /* Partial pages */
                    struct page *next;
#ifdef CONFIG_64BIT
                    int pages;  /* Nr of pages left */
                    int pobjects;   /* Approximate count */
#else
                    short int pages;
                    short int pobjects;
#endif
                };
            };
            struct kmem_cache *slab_cache; /* not slob */
            /* Double-word boundary */
            void *freelist;     /* first free object */
            union {
                void *s_mem;    /* slab: first object */
                unsigned long counters;     /* SLUB */
                struct {            /* SLUB */
                    unsigned inuse:16;
                    unsigned objects:15;
                    unsigned frozen:1;
                };
            };
        };
        struct {    /* Tail pages of compound page */
            unsigned long compound_head;    /* Bit zero is set */

            /* First tail page only */
            unsigned char compound_dtor;
            unsigned char compound_order;
            atomic_t compound_mapcount;
        };
        struct {    /* Second tail page of compound page */
            unsigned long _compound_pad_1;  /* compound_head */
            unsigned long _compound_pad_2;
            struct list_head deferred_list;
        };
        struct {    /* Page table pages */
            unsigned long _pt_pad_1;    /* compound_head */
            pgtable_t pmd_huge_pte; /* protected by page->ptl */
            unsigned long _pt_pad_2;    /* mapping */
            union {
                struct mm_struct *pt_mm; /* x86 pgds only */
                atomic_t pt_frag_refcount; /* powerpc */
            };
#if ALLOC_SPLIT_PTLOCKS
            spinlock_t *ptl;
#else
            spinlock_t ptl;
#endif
        };
        struct {    /* ZONE_DEVICE pages */
            /** @pgmap: Points to the hosting device page map. */
            struct dev_pagemap *pgmap;
            unsigned long hmm_data;
            unsigned long _zd_pad_1;    /* uses mapping */
        };

        /** @rcu_head: You can use this to free a page by RCU. */
        struct rcu_head rcu_head;
    };

    union {     /* This union is 4 bytes in size. */
        /*
         * If the page can be mapped to userspace, encodes the number
         * of times this page is referenced by a page table.
         */
        atomic_t _mapcount;

        /*
         * If the page is neither PageSlab nor mappable to userspace,
         * the value stored here may help determine what this page
         * is used for.  See page-flags.h for a list of page types
         * which are currently stored here.
         */
        unsigned int page_type;

        unsigned int active;        /* SLAB */
        int units;          /* SLOB */
    };

    /* Usage count. *DO NOT USE DIRECTLY*. See page_ref.h */
    atomic_t _refcount;
#ifdef CONFIG_MEMCG
    struct mem_cgroup *mem_cgroup;
#endif
    /*
     * On machines where all RAM is mapped into kernel address space,
     * we can simply calculate the virtual address. On machines with
     * highmem some memory is mapped into kernel virtual memory
     * dynamically, so we need a place to store that address.
     * Note that this field could be 16 bits on x86 ... ;)
     *
     * Architectures with slow multiplication can define
     * WANT_PAGE_VIRTUAL in asm/page.h
     */
#if defined(WANT_PAGE_VIRTUAL)
    void *virtual;          /* Kernel virtual address (NULL if
                       not kmapped, ie. highmem) */
#endif /* WANT_PAGE_VIRTUAL */

#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
    int _last_cpupid;
#endif
} _struct_page_alignment;

2.3 頁表

??頁表建立了虛擬地址到物理地址的映射關(guān)聯(lián)宫屠。其通過radix tree來快速查找虛擬地址對應(yīng)的物理地址,內(nèi)核空間的映射基本是一致性映射滑蚯。內(nèi)核內(nèi)存管理總是假定使用四級頁表浪蹂,但有些體系結(jié)構(gòu)并不是采用四級頁表,比如IA-32系統(tǒng)告材,只有2級頁表坤次,所以體系結(jié)構(gòu)需要對于對于第三、第四級頁表進(jìn)行模擬處理斥赋。這里面比較復(fù)雜缰猴,先只考慮四級頁表的情況。

內(nèi)存地址分解
分解虛擬內(nèi)存地址

地址空間包括5個部分疤剑,前四個部分用于選擇頁滑绒,最后一個部分用于選擇頁內(nèi)位置,BITS_PER_LONG用于表示地址空間長度隘膘,PGD:全局目錄項疑故;PUD:上層目錄項;PMD:中間頁目錄項弯菊;PTE:直接頁表項纵势。

3. 初始化內(nèi)存管理

內(nèi)核內(nèi)存初始化

setup_arch:初始化自舉分配器;
setup_per_cpu_areas:在SMP系統(tǒng)中為每個CPU分配一些PER_CPU的靜態(tài)宏變量的副本管钳;
build_all_zonelists:構(gòu)建各個節(jié)點和內(nèi)存域钦铁,在NUMA計算機(jī)中,還會建立節(jié)點的備用節(jié)點才漆;
mem_init: 特定于體系結(jié)構(gòu)牛曹,將內(nèi)存分配器從bootmem遷移到真實的內(nèi)存分配函數(shù)。
setup_per_cpu_pageset:初始化高速緩存及slab分配器醇滥。
這里需要特殊說明的就是build_all_zonelists中的備用節(jié)點的建立躏仇,在UMA中will do nothing恋脚,但是在NUMA會建立起相關(guān)zonelist結(jié)構(gòu)
arch_call_rest_init:做一些掃尾工作,其中最重要的就是會初始化各個pages并分配到伙伴系統(tǒng)中焰手,具體到在伙伴系統(tǒng)相關(guān)知識中詳細(xì)介紹糟描。

typedef struct pglist_data {
        ...
    struct zonelist node_zonelists[MAX_ZONELISTS];
        ...
}
struct zonelist {
    struct zoneref _zonerefs[MAX_ZONES_PER_ZONELIST + 1];
};
struct zoneref {
    struct zone *zone;  /* Pointer to actual zone */
    int zone_idx;       /* zone_idx(zoneref->zone) */
};
void __ref build_all_zonelists(pg_data_t *pgdat)
{
    if (system_state == SYSTEM_BOOTING) {
        build_all_zonelists_init(); /* __build_all_zonelists(NULL); */
    } else {
        __build_all_zonelists(pgdat);
        /* cpuset refresh routine should be here */
    }
    ...
}
static void __build_all_zonelists(void *data)
{
    ...
    if (self && !node_online(self->node_id)) { / * non-booting*/
        build_zonelists(self);
    } else {  / * when booting, init all nodes*/
        for_each_online_node(nid) {
            pg_data_t *pgdat = NODE_DATA(nid); /* 根據(jù)node_id 查詢pg_data_t*/
            build_zonelists(pgdat);
        }
                ...
    }
        ...
}
static void build_zonelists(pg_data_t *pgdat)
{
    static int node_order[MAX_NUMNODES]; /* 備用節(jié)點,按優(yōu)先級排序书妻,優(yōu)先級的計算與節(jié)點的到當(dāng)前節(jié)點的距離船响,節(jié)點的負(fù)載相關(guān); 具體見find_next_best_node */
    int node, load, nr_nodes = 0;
    nodemask_t used_mask;
    int local_node, prev_node;

    /* NUMA-aware ordering of nodes */
    local_node = pgdat->node_id;
    load = nr_online_nodes; /* 可用的內(nèi)存節(jié)點數(shù) */
    prev_node = local_node;
    nodes_clear(used_mask);

    memset(node_order, 0, sizeof(node_order));
    while ((node = find_next_best_node(local_node, &used_mask)) >= 0) {
        /*
         * We don't want to pressure a particular node.
         * So adding penalty to the first node in same
         * distance group to make it round-robin.
         */
        if (node_distance(local_node, node) !=
            node_distance(local_node, prev_node))
            node_load[node] = load;

        node_order[nr_nodes++] = node;
        prev_node = node;
        load--;
    }
    build_zonelists_in_node_order(pgdat, node_order, nr_nodes);
    build_thisnode_zonelists(pgdat);
}

static void build_zonelists_in_node_order(pg_data_t *pgdat, int *node_order,
        unsigned nr_nodes)
{
    struct zoneref *zonerefs;
    int i;
    zonerefs = pgdat->node_zonelists[ZONELIST_FALLBACK]._zonerefs;
    for (i = 0; i < nr_nodes; i++) {
        int nr_zones;
        pg_data_t *node = NODE_DATA(node_order[i]);
        nr_zones = build_zonerefs_node(node, zonerefs); // 分配了 nr_zones個zone躲履,zonerefs需要向后移nr_zones
        zonerefs += nr_zones;
    }
    zonerefs->zone = NULL;
    zonerefs->zone_idx = 0;
}
static int build_zonerefs_node(pg_data_t *pgdat, struct zoneref *zonerefs)
{
    struct zone *zone;
    enum zone_type zone_type = MAX_NR_ZONES; // 內(nèi)存域種類
    int nr_zones = 0;
    do {
        zone_type--; // 內(nèi)存域分配由廉價到昂貴
        zone = pgdat->node_zones + zone_type;
        if (managed_zone(zone)) { // 確保zone存在
            zoneref_set_zone(zone, &zonerefs[nr_zones++]);
            check_highest_zone(zone_type); // 檢查并設(shè)置非moveable的最高的zone
        }
    } while (zone_type);
    return nr_zones;
}

假設(shè)一個有四個節(jié)點的NUMA計算機(jī)其最終備用域的分配可能類似于下圖:


連續(xù)填充備用域示意圖
linux內(nèi)核起始段物理內(nèi)存布局
linux內(nèi)核進(jìn)程起始段物理內(nèi)存布局

該圖給出了內(nèi)核內(nèi)存的前幾兆字節(jié)见间,這些字節(jié)加載了內(nèi)核進(jìn)程的代碼段,只讀數(shù)據(jù)段工猜,初始化數(shù)據(jù)段米诉。第一個頁幀主要供BIOS使用,后續(xù)的640Kib也基本不使用篷帅,用于映射各種ROM(系統(tǒng)BIOS和顯卡ROM)史侣。
在IA-32系統(tǒng)中一般是從0x100000開始加載內(nèi)核代碼。


內(nèi)存初始化流程圖

該圖給出了系統(tǒng)加載內(nèi)核內(nèi)存管理模塊的流程魏身。
paging_init負(fù)責(zé)初始化內(nèi)核頁表并啟用內(nèi)存分頁惊橱;
最終分配完后的內(nèi)核內(nèi)存布局如圖:


內(nèi)核內(nèi)存地址空間

內(nèi)核的普通內(nèi)存(normalmem)大部分內(nèi)存是直接直接映射的。前面說到內(nèi)核地址只能通過直接映射使用前896MiB的數(shù)據(jù)箭昵,后續(xù)的128M被叫做高端內(nèi)存(highmem)税朴,而高端內(nèi)存有三種訪問方式,vmalloc:可以在這個區(qū)域分配不連續(xù)的內(nèi)存家制;持久映射:用于將高端內(nèi)存中的非持久頁映射到內(nèi)核中正林;固定映射:與固定的內(nèi)核物理地址關(guān)聯(lián),但具體關(guān)聯(lián)的頁幀可以自由選擇颤殴。
虛擬地址和物理地址的管理

??內(nèi)核初始化完成后卓囚,物理內(nèi)存管理的管理基本是由伙伴系統(tǒng)承擔(dān),伙伴系統(tǒng)以一種非常簡單而高效的方式伴隨了linux40多年诅病,結(jié)合了優(yōu)秀內(nèi)存分配器的特點:速度與效率哪亿。而內(nèi)核還為內(nèi)核提供了非連續(xù)分配內(nèi)存及管理緩存及小額內(nèi)存分配的slab,slub及slob,這些將后續(xù)一一描述贤笆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蝇棉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子芥永,更是在濱河造成了極大的恐慌篡殷,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件埋涧,死亡現(xiàn)場離奇詭異板辽,居然都是意外死亡奇瘦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門劲弦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耳标,“玉大人,你說我怎么就攤上這事邑跪〈纹拢” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵画畅,是天一觀的道長砸琅。 經(jīng)常有香客問我,道長轴踱,這世上最難降的妖魔是什么症脂? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮淫僻,結(jié)果婚禮上稚照,老公的妹妹穿的比我還像新娘昌渤。我一直安慰自己桥状,他們只是感情好热康,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布宣赔。 她就那樣靜靜地躺著掀泳,像睡著了一般懒熙。 火紅的嫁衣襯著肌膚如雪罪针。 梳的紋絲不亂的頭發(fā)上蕾殴,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天笑撞,我揣著相機(jī)與錄音,去河邊找鬼钓觉。 笑死茴肥,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的荡灾。 我是一名探鬼主播瓤狐,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼批幌!你這毒婦竟也來了础锐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤荧缘,失蹤者是張志新(化名)和其女友劉穎皆警,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體截粗,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡信姓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年鸵隧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片意推。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡豆瘫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出左痢,到底是詐尸還是另有隱情靡羡,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布俊性,位于F島的核電站略步,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏定页。R本人自食惡果不足惜趟薄,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望典徊。 院中可真熱鬧杭煎,春花似錦、人聲如沸卒落。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽儡毕。三九已至也切,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間腰湾,已是汗流浹背雷恃。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留费坊,地道東北人倒槐。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像附井,于是被迫代替她去往敵國和親讨越。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345