swap分析及其使用


 

什么是swap

swap主要是在內存不夠用的時候,將部分內存上的數據交換到swap空間上,以便讓系統不會因為內存不夠用而導致oom或者更致命的情況出現。當內存使用存在壓力的時候,開始觸發內存回收行為,就可能會使用swap空間。

內核將很少使用的部分內存換出到塊設備,相當於提供了更多的主內存,這種機制成為頁交換(swapping)或者換頁(paging),由內核實現,對應用程序是透明的。

如果一個很少使用的頁的后備存儲器是一個塊設備,那么就無需換出被修改的頁,而是可以直接與塊設備同步。騰出的頁幀可以重用,如果再次需要修改數據,可以從來源重新建立該頁。

如果頁的后備存儲器是一個文件,但不能在內存中修改,那么在當前不需要的情況下,可以直接丟棄該頁。

以上這三種技術,連同選擇很少使用頁的策略,統稱為頁面回收。

為什么要進行內存回收?

1.內核需要為突發到來的內存申請提供足夠的內存,所以一般情況下保證有足夠的free空間對於內核來說是必要的。
  另外,Linux內核使用cache策略雖然是不用白不用,內核會使用內存中的page cache對部分文件進行緩存,一邊提升文件的讀寫效率。
  所以內核有必要設計一個周期行回收內存機制,以便cache的使用和其他相關內存的使用不至於讓系統的剩余內存長期處於很少的狀態。

2.當真的有大於空閑內存的申請到來的是偶,會觸發強制內存回收。

所以內核在應對這兩類回收的需求下,分別實現兩種不同的機制:

一個是使用kswapd進程對內存進行周期檢查,以保證平常狀態下剩余內存盡可能夠用。
另一個是頁面回收(page reclaim),就是當內存分配時沒有空閑內存可以滿足要求時,觸發直接內存回收。

這兩種內存回收的觸發路徑不同:

kswapd作為一個后台守護進程,會定期檢查內存的使用情況,並檢測即將發生的內存不足。可使用該守護進程換出頁,並釋放那些最不常用的。
    參見mm/vmscan.c中的kswapd()主邏輯。

kswapd
    -->balance_pgdat
        -->kswapd_shrink_zone
            -->shrink_zone
                -->shrink_lruvec

如果內存檢測到在某個操作期間內存嚴重不足,將調用try_to_free_pages。該函數檢查當前內存域中所有頁,並釋放最不常用的那些。
    參見內核代碼中的mm/page_alloc.c中的__alloc_pages_slowpath方法。

__alloc_pages_nodemask
    -->__alloc_pages_slowpath
        -->__alloc_pages_direct_reclaim  直接頁面回收然后分配內存
            -->__perform_reclaim  執行同步直接頁面回收
                -->try_to_free_pages 
                    -->do_try_to_free_pages
                        -->shrink_zones
                            -->shrink_zone
                                -->shrink_lruvec

這兩個方法實際進行內存回收的過程殊途同歸,最終頭時調用shrink_zone()方法針對每個zone的內存頁縮減。

這個方法中在調用shrink_lruvec()這個方法對每個組織頁的鏈表進行進程檢查,找到這個線索之后,我們就可以清晰地看到內存回收操作究竟這對的page有哪些了。

static void shrink_lruvec(struct lruvec *lruvec, int swappiness,
              struct scan_control *sc, unsigned long *lru_pages)
{

    while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
                    nr[LRU_INACTIVE_FILE]) {
        unsigned long nr_anon, nr_file, percentage;
        unsigned long nr_scanned;

        for_each_evictable_lru(lru) {
            if (nr[lru]) {
                nr_to_scan = min(nr[lru], SWAP_CLUSTER_MAX);
                nr[lru] -= nr_to_scan;

                nr_reclaimed += shrink_list(lru, nr_to_scan,
                                lruvec, sc);
            }
        }

}

內存回收主要需要進行少秒的鏈表有如下4個:

anon的inactive,anon的active,file的inactive,file的active。

就是說內存回收主要針對的就是內存中的文件頁(file cache)和匿名頁。

關於活躍還是不活躍的判斷內核會使用lru算法進行並行處理並進行標記。

#define LRU_BASE 0
#define LRU_ACTIVE 1
#define LRU_FILE 2

enum lru_list {
    LRU_INACTIVE_ANON = LRU_BASE,
    LRU_ACTIVE_ANON = LRU_BASE + LRU_ACTIVE,
    LRU_INACTIVE_FILE = LRU_BASE + LRU_FILE,
    LRU_ACTIVE_FILE = LRU_BASE + LRU_FILE + LRU_ACTIVE,
    LRU_UNEVICTABLE,
    NR_LRU_LISTS
};

整個掃描的過程分幾個循環:
1.首先掃描每個zone刪的cgroup組;
2.然后再以cgroup的內存為單元進行page鏈表的掃描;
3.內核會先掃描anon的active鏈表,將不頻繁的放進inactive鏈表中,然后掃描inactive鏈表,將里面活躍的移回active鏈表中;
4.進行swap的時候,先對inactive的頁進行換出;
5.如果是file的文件映射page頁,則判斷其是否為臟數據,如果是臟數據就寫回,不是臟數據可以直接釋放。

這樣看來,內存回收這個行為會對兩種內存的使用進行回收:

一種是anon的匿名頁內存,主要回收手段是swap;另一種是file-backed的文件映射頁,主要釋放手段是寫回和清空。

內存對匿名頁和文件緩存一共用了四條鏈表進行組織,回收過程主要是針對這四條鏈表進行掃描和操作。

kswapd什么時候進行swap操作?

內核的兩種內存回收機制kswapd周期檢查和直接內存回收,直接內存回收比較好理解,當申請的內存大於剩余內存的時候,就會觸發直接回收。

kswapd進程在周期檢查的時候觸發回收的條件是什么呢?

kswapd進程要周期對內存進行檢測,達到一定閾值的時候開始進行內存回收。這個所謂的閾值可以理解為內存目前的使用壓力。雖然我們還有剩余內存,但是當剩余內存比較小的時候,就是內存壓力較大的時候,就應該開始試圖回收寫內存了,這樣才能保證系統盡可能有足夠的內存給突發的內存申請所使用。

基於swappiness調優

詳情請參考:http://blog.csdn.net/tenfyguo/article/details/50185915

swappiness是一個swap相關百分比參數,默認值是60,范圍是0-100。

This control is used to define how aggressive the kernel will swap memory pages.  Higher values will increase agressiveness, lower values decrease the amount of swap.  A value of 0 instructs the kernel not to initiate swap until the amount of free and file-backed pages is less than the high water mark in a zone.

從上面這段話可知,swappiness表示內核swap內存頁的積極程度。值越高越是積極的進行swap;降低表示積極性越低。當swappiness值為0是,不是不進行swap,只是一個zone中內存的free和file-backed頁低於高水位標記才會進行swap。

shrink_lruvec()調用get_scan_count()方法,get_scan_count用於決定anon和文件LRU列表被掃描的積極程度。swappiness參數實際上是知道內核在清空內存的時候,是更傾向於清空file-backed內存還是匿名頁的swap。

static void get_scan_count(struct lruvec *lruvec, int swappiness,
               struct scan_control *sc, unsigned long *nr,
               unsigned long *lru_pages)
{
    struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat;
    u64 fraction[2];
    u64 denominator = 0;    /* gcc */
    struct zone *zone = lruvec_zone(lruvec);
    unsigned long anon_prio, file_prio;
    enum scan_balance scan_balance;
    unsigned long anon, file;
    bool force_scan = false;
    unsigned long ap, fp;
    enum lru_list lru;
    bool some_scanned;
    int pass;

    /*
     * If the zone or memcg is small, nr[l] can be 0.  This
     * results in no scanning on this priority and a potential
     * priority drop.  Global direct reclaim can go to the next
     * zone and tends to have no problems. Global kswapd is for
     * zone balancing and it needs to scan a minimum amount. When
     * reclaiming for a memcg, a priority drop can cause high
     * latencies, so it's better to scan a minimum amount there as
     * well.
     */
    if (current_is_kswapd()) {
        if (!zone_reclaimable(zone))
            force_scan = true;
        if (!mem_cgroup_lruvec_online(lruvec))
            force_scan = true;
    }
    if (!global_reclaim(sc))
        force_scan = true;

    /* If we have no swap space, do not bother scanning anon pages. */
    if (!sc->may_swap || (get_nr_swap_pages() <= 0)) {
        scan_balance = SCAN_FILE;
        goto out;
    }

    /*
     * Global reclaim will swap to prevent OOM even with no
     * swappiness, but memcg users want to use this knob to
     * disable swapping for individual groups completely when
     * using the memory controller's swap limit feature would be
     * too expensive.
     */
    if (!global_reclaim(sc) && !swappiness) {
        scan_balance = SCAN_FILE;
        goto out;
    }

    /*
     * Do not apply any pressure balancing cleverness when the
     * system is close to OOM, scan both anon and file equally
     * (unless the swappiness setting disagrees with swapping).
     */
    if (!sc->priority && swappiness) {
        scan_balance = SCAN_EQUAL;
        goto out;
    }

    /*
     * Prevent the reclaimer from falling into the cache trap: as
     * cache pages start out inactive, every cache fault will tip
     * the scan balance towards the file LRU.  And as the file LRU
     * shrinks, so does the window for rotation from references.
     * This means we have a runaway feedback loop where a tiny
     * thrashing file LRU becomes infinitely more attractive than
     * anon pages.  Try to detect this based on file LRU size.
     */
    if (global_reclaim(sc)) {
        unsigned long zonefile;
        unsigned long zonefree;

        zonefree = zone_page_state(zone, NR_FREE_PAGES);
        zonefile = zone_page_state(zone, NR_ACTIVE_FILE) +
               zone_page_state(zone, NR_INACTIVE_FILE);

        if (unlikely(zonefile + zonefree <= high_wmark_pages(zone))) {
            scan_balance = SCAN_ANON;
            goto out;
        }
    }如果觸發的是全局回收,並且zonefile+zonefree<=high_wmark_pages(zone)條件成立時,就將scan_banlance這個標記置為SCAN_ANON。后續處理scan_balance的時候,則一定會進行針對匿名頁的swap操作。
再來看看zonefile+zonefree<=high_wmark_pages(zone)這個公式就能理解了。zonefile是內存中文件映射的總量,zonefree相當於剩余內存總量。內核一般認為,如果zonefile還有的話,就盡量通過清空文件緩存獲得部分內存,而不必只使用swap方式對anon內存進行交換。
這樣是為了防止進入cache陷阱。這個判斷對系統的影響是,swappiness為0時,有剩余內存的情況下也可能發生交換。

    /*
     * There is enough inactive page cache, do not reclaim
     * anything from the anonymous working set right now.
     */
    if (!inactive_file_is_low(lruvec)) {
        scan_balance = SCAN_FILE;
        goto out;
    }

    scan_balance = SCAN_FRACT;

    /*
     * With swappiness at 100, anonymous and file have the same priority.
     * This scanning priority is essentially the inverse of IO cost.
     */
    anon_prio = swappiness;
    file_prio = 200 - anon_prio;

1.如果swappiness設置為100,那么匿名頁和文件將用同樣的優先級進行回收。
   很明顯,使用清空文件的的方式將有利於減輕內存回收時可能造成的IO壓力。因為如果file-backed中的數據不是臟數據的話,那么可以不用寫回,這樣就沒有IO發生,而一旦進行交換,就一定會造成IO。所以系統默認將swappiness的值設置為60,這樣回收內存時,對file-backed的文件cache的清空比例會更大,內核更傾向於進行緩存清空而不是交換。

2.如果swappiness值是60,內核回收的時候也不是完全按照60:140比例清空。在計算具體回收大小的時候,還需要參考當前內存使用的其他信息。
   我們在此需要明確的概念是:swappiness的值是用來控制內存回收時,回收的匿名頁更多一些還是禍首的file-backed更多一些。

3.swappiness為0的話,也不是根本不進行swap。
   內存真的不夠用時,還是會進行swap。比如為global_reclaim的時候,還是會導致在處理scan_balance的時候進行SCAN_ANON。

    /*
     * OK, so we have swap space and a fair amount of page cache
     * pages.  We use the recently rotated / recently scanned
     * ratios to determine how valuable each cache is.
     *
     * Because workloads change over time (and to avoid overflow)
     * we keep these statistics as a floating average, which ends
     * up weighing recent references more than old ones.
     *
     * anon in [0], file in [1]
     */

    anon  = get_lru_size(lruvec, LRU_ACTIVE_ANON) +
        get_lru_size(lruvec, LRU_INACTIVE_ANON);
    file  = get_lru_size(lruvec, LRU_ACTIVE_FILE) +
        get_lru_size(lruvec, LRU_INACTIVE_FILE);

    spin_lock_irq(&zone->lru_lock);
    if (unlikely(reclaim_stat->recent_scanned[0] > anon / 4)) {
        reclaim_stat->recent_scanned[0] /= 2;
        reclaim_stat->recent_rotated[0] /= 2;
    }

    if (unlikely(reclaim_stat->recent_scanned[1] > file / 4)) {
        reclaim_stat->recent_scanned[1] /= 2;
        reclaim_stat->recent_rotated[1] /= 2;
    }

    /*
     * The amount of pressure on anon vs file pages is inversely
     * proportional to the fraction of recently scanned pages on
     * each list that were recently referenced and in active use.
     */
    ap = anon_prio * (reclaim_stat->recent_scanned[0] + 1);
    ap /= reclaim_stat->recent_rotated[0] + 1;

    fp = file_prio * (reclaim_stat->recent_scanned[1] + 1);
    fp /= reclaim_stat->recent_rotated[1] + 1;
    spin_unlock_irq(&zone->lru_lock);

    fraction[0] = ap;
    fraction[1] = fp;
    denominator = ap + fp + 1;
out:
    some_scanned = false;
    /* Only use force_scan on second pass. */
    for (pass = 0; !some_scanned && pass < 2; pass++) {
        *lru_pages = 0;
        for_each_evictable_lru(lru) {
            int file = is_file_lru(lru);
            unsigned long size;
            unsigned long scan;

            size = get_lru_size(lruvec, lru);
            scan = size >> sc->priority;

            if (!scan && pass && force_scan)
                scan = min(size, SWAP_CLUSTER_MAX);

            switch (scan_balance) {
            case SCAN_EQUAL:
                /* Scan lists relative to size */
                break;
            case SCAN_FRACT:
                /*
                 * Scan types proportional to swappiness and
                 * their relative recent reclaim efficiency.
                 */
                scan = div64_u64(scan * fraction[file],
                            denominator);
                break;
            case SCAN_FILE:
            case SCAN_ANON:
                /* Scan one type exclusively */
                if ((scan_balance == SCAN_FILE) != file) {
                    size = 0;
                    scan = 0;
                }
                break;
            default:
                /* Look ma, no brain */
                BUG();
            }

            *lru_pages += size;
            nr[lru] = scan;

            /*
             * Skip the second pass and don't force_scan,
             * if we found something to scan.
             */
            some_scanned |= !!scan;
        }
    }
}

可以使用sysctl vm.swappiness=10對swappiness進行設置。

dirty_ratio

同步刷臟頁,會阻塞應用程序。這個參數控制文件系統的同步寫緩沖區的大小,單位是百分比,表示當寫緩沖區使用到系統內存多少的時候(即指定了當文件系統緩存臟頁數量達到系統內存百分比時),開始向磁盤寫出數據,及系統不得不開始處理緩存臟頁,在此過程中很多應用程序可能會因為系統轉而處理文件I/O而阻塞變慢。

增大會使系統內存更多用於磁盤寫緩沖,也可以極大提高系統的寫性能。

dirty_background_ratio

異步刷臟頁,不會阻塞應用程序。這個參數控制文件系統的后台進程,在合適刷新磁盤。當寫緩沖使用到系統內存一定百分比的時候,就會觸發pdflush/flush/kdmflush等后台回寫進程運行,將一定緩存的臟頁異步地輸入外存。

一般dirty_ratio比dirty_background_radio要大,先達到dirty_background_ratio的條件然后觸發flush進程進行異步的回寫操作,但是這一過程應用進程仍然可以進行寫操作,如果多個應用程序寫入的量大於刷出的量那自然會達到dirty_ratio的標准,此時操作系統會進入同步刷出臟頁的過程,阻塞應用進程。

增大會使更多系統內存用於磁盤寫緩沖。

dirty_expire_centisecs

申明Linux內核寫緩沖區里面的數據多舊了之后,pdflush進程就開始考慮寫到磁盤中去,單位是1/100秒。缺省是3000,即20秒的緩存就會被刷新到磁盤。如果太小,刷新磁盤就會比較頻繁,導致I/O占用太多時間。如過太大,在某些異常情況會造成數據丟失,同時暫用太多內存。

dirty_writeback_centisecs

這個參數控制內核額臟數據樹新進程pdflush的運行間隔,單位是1/100秒,缺省是500,即5秒。

vfs_cache_pressure

設置了虛擬內存回收directory和inode緩存的傾向,這個值越大,越傾向於回收。

缺省值為100;低於100,將導致內核更傾向於保留directory和inode cache;高於100,將導致內核傾向於回收directory和inode cache。

 

以上這些數據還是要根據系統實際內存以及不同的工作場景進行調優。

 

內存水位標記(watermark)

Linux為內存的使用設置了三種內存水位標記:high、low、min。
high:剩余的內存在high以上表示內存剩余較多,目前內存使用壓力不大。
high-low:表示剩余內存存在一定壓力。
low-min:表示內存開始使用有較大壓力,剩余內存不多了。
min:是最小水位標記,當剩余內存達到這個狀態時,就說明內存面臨很大壓力。小於min這部分內存,內核是保留給特定情況下使用的,一般不分配。

內存回收行為就是基於剩余內存的水位標記進行的:

當系統內存低於watermark[low]的時候,內核的kswapd開始起作用,進行內存回收。直到剩余內存達到watermark[high]的時候停止。

如果內存消耗導致達到了或者低於watermark[min]時,就會觸發直接回收(direct reclaim)。

min_free_kbytes

內存的watermark標記是根據當前內存總大小和min_free_kbytes進行運算的來的。

/proc/sys/vm/min_free_kbytes決定了每個zone的watermark[min]的大小,然后根據min的大小和每個zone內存大小分別算出每個zone的low和high水位標記。

init_per_zone_wmark_min  初始化min_free_kbytes
    -->setup_per_zone_wmarks
        -->__setup_per_zone_wmarks  根據min_free_kbytes計算low和high的值

下面來分析一下low和high水位值是如何計算的:

static void __setup_per_zone_wmarks(void)
{
    unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10);
    unsigned long pages_low = extra_free_kbytes >> (PAGE_SHIFT - 10);
    unsigned long lowmem_pages = 0;
    struct zone *zone;
    unsigned long flags;

    /* Calculate total number of !ZONE_HIGHMEM pages */
    for_each_zone(zone) {  針對ZONE_HIGHMEM特殊處理
        if (!is_highmem(zone))
            lowmem_pages += zone->managed_pages;
    }

    for_each_zone(zone) {  遍歷所有zone
        u64 min, low;

        spin_lock_irqsave(&zone->lock, flags);
        min = (u64)pages_min * zone->managed_pages;
        do_div(min, lowmem_pages);  針對非HIGHMEM,min即為pages_min。
        low = (u64)pages_low * zone->managed_pages;
        do_div(low, vm_total_pages);  針對非HIGHMEM,low為0.

        if (is_highmem(zone)) {
            /*
             * __GFP_HIGH and PF_MEMALLOC allocations usually don't
             * need highmem pages, so cap pages_min to a small
             * value here.
             *
             * The WMARK_HIGH-WMARK_LOW and (WMARK_LOW-WMARK_MIN)
             * deltas control asynch page reclaim, and so should
             * not be capped for highmem.
             */
            unsigned long min_pages;

            min_pages = zone->managed_pages / 1024;
            min_pages = clamp(min_pages, SWAP_CLUSTER_MAX, 128UL);
            zone->watermark[WMARK_MIN] = min_pages;
        } else {
            /*
             * If it's a lowmem zone, reserve a number of pages
             * proportionate to the zone's size.
             */
            zone->watermark[WMARK_MIN] = min;
        }

        zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) +
                    low + (min >> 2);  low水位線位於min的1.25倍地方
        zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) +
                    low + (min >> 1);  high水位線位於min的1.5倍地方

        __mod_zone_page_state(zone, NR_ALLOC_BATCH,
            high_wmark_pages(zone) - low_wmark_pages(zone) -
            atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH]));

        spin_unlock_irqrestore(&zone->lock, flags);
    }

    /* update totalreserve_pages */
    calculate_totalreserve_pages();
}

通過cat /proc/zoneinfo可以看到不同zone的watermark:

cat /proc/zoneinfo
Node 0, zone      DMA
  pages free     3840
        min      43
        low      53 = 43+0+(43/4)=53
        high     64 =43+0+(43/2)=64
        scanned  0
        spanned  4095
        present  3996
        managed  3840

Node 0, zone    DMA32
  pages free     176977
        min      8215
        low      10268
        high     12322
        scanned  0
        spanned  1044480
        present  744139
        managed  724056

Node 0, zone   Normal
  pages free     168622
        min      8636
        low      10795
        high     12954
        scanned  0
        spanned  779776
        present  779776
        managed  755387

zone_reclaim_mode

當一個內存區域內部的內存耗盡時,是從其內部進行內存回收還是可以從其他zone進行回收的選項。在申請內存時(get_page_from_freelist()),內核在當前zone內沒有足夠的內存可用的情況下,會根據zone_reclaim_mode的設置來決策是從下一個zone找空閑內存還是在zone內部進行回收。

0:意味着關閉zone_claim模式,可以從其他zone或NUMA節點回收內存。
1:打開zone_claim模式,這樣內存回收只會發生在本地節點內。
2:在本地回收內存時,可以將可以將cache中的臟數據回寫硬盤,以回收內存。
3:可以用swap方式回收內存。

不同的參數配置會在NUMA環境中對其他內存節點的內存使用產生不同的影響,大家可以根據自己的情況進行設置以優化你的應用。
默認情況下,zone_reclaim模式是關閉的。這在很多應用場景下可以提高效率,比如文件服務器,或者依賴內存中cache比較多的應用場景。
這樣的場景對內存cache速度的依賴要高於進程進程本身對內存速度的依賴,所以我們寧可讓內存從其他zone申請使用,也不願意清本地cache。
如果確定應用場景是內存需求大於緩存,而且盡量要避免內存訪問跨越NUMA節點造成的性能下降的話,則可以打開zone_reclaim模式。
此時頁分配器會優先回收容易回收的可回收內存(主要是當前不用的page cache頁),然后再回收其他內存。
打開本地回收模式的寫回可能會引發其他內存節點上的大量的臟數據寫回處理。如果一個內存zone已經滿了,那么臟數據的寫回也會導致進程處理速度收到影響,產生處理瓶頸。
這會降低某個內存節點相關的進程的性能,因為進程不再能夠使用其他節點上的內存。但是會增加節點之間的隔離性,其他節點的相關進程運行將不會因為另一個節點上的內存回收導致性能下降。
除非針對本地節點的內存限制策略或者cpuset配置有變化,對swap的限制會有效約束交換只發生在本地內存節點所管理的區域上。

page-cluster

page-cluster是用來控制從swap空間換入數據的時候,一次連續讀取的頁數這相當於對交換空間的預讀取。這里的連續指的是swap空間上的連續,而不是內存地址上的連續。

這個文件中設置的是2的指數。0,則預讀取1頁;3,則預讀取8頁。

創建、刪除swap分區

查看swap相關信息

swapon –s和cat /proc/swaps的結果是一樣的,可以用於查看當前系統的swap分區總結。

Filename                Type        Size    Used    Priority
/dev/sdb1                               partition    7999484    576596    -1

free -m用於顯示系統空閑和使用的內存量,其中包括swap信息。

             total       used       free     shared    buffers     cached
Mem:          5794       5590        203        237       1843       1755
-/+ buffers/cache:       1990       3803
Swap:         7811        563       7248

創建swap分區

有兩種方式創建swap分區:一種是基於物理分區,另一種是基於一個文件。

基於物理分區創建

  • 創建一個swap分區:fdisk -l /dev/sdb1
  • 格式化分區:mkswap -c v1 /dev/sdb1
  • 修改/etc/fstab文件,增加:

    # /etc/fstab: static file system information.
    #
    # Use 'blkid' to print the universally unique identifier for a
    # device; this may be used with UUID= as a more robust way to name devices
    # that works even if disks are added and removed. See fstab(5).
    #
    # <file system> <mount point>   <type>  <options>       <dump>  <pass>
    # swap was on /dev/sdb1 during installation
    UUID=47b966f2-8157-4650-a2c2-32f0907081bf none            swap    sw              0       0

  • 激活swap分區:swapon –a /dev/sdb1
  • 查看swap分區:swapon -s 或cat /proc/swaps

基於文件創建

  • dd if=/dev/zero of=/home/lubaoquan/swap/tmp.swap bs=1G count=1,創建空文件
  • mkswap tmp.swap,創建為swap文件

Setting up swapspace version 1, size = 1048572 KiB
no label, UUID=f63f7b37-be4c-4794-b8bd-ddd810a42730

  • swapon /tmp/tmp.swap,激活swap分區
  • 修改/etc/fstab文件
/tmp/tmp.swap swap swap default 0 0
  • 查看swap分區信息swapon –s

Filename                Type        Size    Used    Priority
/dev/sdb1               partition    7999484    583536    -1
/tmp/tmp.swap       file        1048572    0    -2

刪除swap分區

  • swapoff /dev/sdb1
  • 修改/etc/fstab文件

關於swap的一個測試

關閉打開清空swap

sudo swapoff -a關閉swap,然后free –m查看使用情況

             total       used       free     shared    buffers     cached
Mem:          5794       5131        662        361       1002       1858
-/+ buffers/cache:       2270       3523
Swap:            0          0          0

 

sudo swapon -a再打開,查看free -m:

             total       used       free     shared    buffers     cached
Mem:          5794       5139        654        366       1002       1863
-/+ buffers/cache:       2272       3521
Swap:         7811          0       7811

swap變化

使用eat_mem.c不斷分配大內存。

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

int main(int argc, char** argv)

{

int max = -1;

int mb = 0;

    char* buffer;

if(argc > 1)

        max = atoi(argv[1]);

while((buffer=malloc(10*1024*1024)) != NULL && mb != max)

{

        memset(buffer, 0,10*1024*1024);

        mb = mb + 10;

        printf("Allocated %d MB\n", mb);

        sleep(1);

}

    return 0;

}

執行./eat_mem,使用watch 'free -m'可以動態查看Mem和Swap的使用情況:

Every 2.0s: free -m                                                                                                             Fri Jan 20 16:41:31 2017

             total       used       free     shared    buffers     cached
Mem:          5794        691       5102        114         19        218
-/+ buffers/cache:        453       5341
Swap:         7811       1229       6582

在eat_mem執行到11710 MB的時候,被Killed了。

./eat_mem
Allocated 10 MB

Allocated 11660 MB
Allocated 11670 MB
Allocated 11680 MB
Allocated 11690 MB
Allocated 11700 MB
Allocated 11710 MB
Killed

在這個過程中可以看到,Mem的free越來越小,Swap的used空間越來越多,越來越多的內容被置換到Swap區域。

在內容開始置換到swap分區過程中,系統的響應速度越來越慢。最后達到swap分區也承受不了,eat_mem就會被Killed。

swap分區的優先級

在使用多個swap分區或者文件的時候,還有一個優先級的概念。

在swapon的時候,可以使用-p指定相關swap空間的優先級,值越大優先級越高,范圍是-1到32767。

內核在使用swap空間的時候總是先使用優先級搞得空間,后使用優先級低的。

如果把多個swap空間的優先級設置成一樣的,那么swap空間將會以輪詢的方式並行使用。

如果兩個swap放在不同硬盤上,相同優先級可以起到類似的RAID效果,增大swap的讀寫效率。

編程時使用mlock()可以將指定的內存標記為不換出。

參考文檔

http://blog.csdn.net/cyuyan112233/article/details/18803589

http://blog.csdn.net/tenfyguo/article/details/50185915

http://blog.chinaunix.net/uid-24774106-id-3954137.html

http://chuansong.me/n/361090851159


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM