在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

nginx內存池源碼設計

科技綠洲 ? 來源:Linux開發架構之路 ? 作者:Linux開發架構之路 ? 2023-11-13 11:51 ? 次閱讀

造輪子內存池原因引入

作為C/C++程序員, 相較JAVA程序員的一個重大特征是我們可以直接訪問內存, 自己管理內存, 這個可以說是我們的特色, 也是我們的苦楚了.

java可以有虛擬機幫助管理內存, 但是我們只能自己管理內存, 一不小心產生了內存泄漏問題, 又特別是服務器的內存泄漏問題, 進程不死去, 泄漏的內存就一直無法回收.

所以對于內存的管理一直是我們C系列程序員深挖的事情.

所以對于C++有智能指針這個東西. 還有內存池組件. 內存池組件也不能完全避免內存泄漏, 但是它可以很好的幫助我們定位內存泄漏的點, 以及可以減少內存申請和釋放的次數, 提高效率

大量的malloc/free小內存所帶來的弊端

弊端

  1. malloc/free的底層是調用系統調用, 這兩者庫函數是對于系統調用的封裝, 頻繁的系統調用所帶來的用戶內核態切換花費大量時間, 大大降低系統執行效率
  2. 頻繁的申請小內存, 帶來的大量內存碎片, 內存使用率低下且導致無法申請大塊的內存
  3. 沒有內存回收機制, 很容易造成內存泄漏

內存碎片出現原因解釋

  1. 內部內存碎片定義: 已經被分配出去了(明確分配到一個進程), 但是無法被利用的空間
  2. 內存分配的起始地址 一定要是 4, 8, 16整除地址
  3. 內存是按照頁進行分配的, 中間會產生外部內存碎片, 無法分配給進程
  4. 內部內存碎片:頻繁的申請小塊內存導致了內存不連續性,中間的小內存間隙又不足以滿足我們的內存申請要求, 無法申請出去利用起來, 這個就是內部內存碎片.

出現場景

最為典型的場景就是高并發是的頻繁內存申請, 釋放. (http請求) (tcp連接)

大牛解決措施(nginx內存池)

nginx內存池, 公認的設計方式非常巧妙的一款內存池設計組件, 專門針對高并發下面的大量的內存申請釋放而產生的.

在系統層,我們可以使用高性能內存管理組件 Tcmalloc Jemalloc(優化效率和碎片問題)

在應用層: 我們可以根據需求設計內存池進行管理 (高并發可以借助nginx內存池設計)

圖片

內存池技術

啥叫作內存池技術

就是說在真正使用內存之前, 先提前申請分配一定數量的、大小相等(一般情況下)的內存塊留作備用, 當需要分配內存的時候, 直接從內存塊中獲取. 如果內存塊不夠了, 再申請新的內存塊.

內存池: 就是將這些提前申請的內存塊組織管理起來的數據結構

優勢何在:統一對程序所使用的內存進行統一的分配和回收, 提前申請的塊, 然后將塊中的內存合理的分配出去, 極大的減少了系統調用的次數. 提高了內存利用率. 統一的內存分配回收使得內存泄漏出現的概率大大降低

內存池技術為啥可以解決上文弊端

高并發時系統調用頻繁(malloc free頻繁),降低了系統的執行效率

  • 內存池提前預先分配大塊內存,統一釋放,極大的減少了malloc 和 free 等函數的調用。

頻繁使用時增加了系統內存的碎片,降低內存使用效率

  • 內存池每次請求分配大小適度的內存塊,最大避免了碎片的產生

沒有內存回收機制,容易造成內存泄漏

  • 在生命周期結束后統一釋放內存,極大的避免了內存泄露的發生

高并發內存池nginx內存池源碼刨析

啥是高并發

系統能夠同時并行處理很多請求就是高并發

高并發具備的特征

  • 響應時間短
  • 支持并發用戶數高
  • 支持用戶接入量高
  • 連接建立時間短

nginx_memory_pool為啥就適合高并發

內存池生存時間應該盡可能短,與請求或者連接具有相同的周期

減少碎片堆積和內存泄漏

避免不同請求連接之間互相影響

一個連接或者一個請求就創建一個內存池專門為其服務, 內存池的生命周期和連接的生命周期保持一致.

仿寫nginx內存池

實現思路

  • 對于每個請求或者連接都會建立相應的內存池,建立好內存池之后,我們可以直接從內存池中申請所需要的內存,不用去管內存的釋放,當內存池使用完成之后一次性銷毀內存池。
  • 區分大小內存塊的申請和釋放,大于內存池塊最大尺寸的定義為大內存塊,使用單獨的大內存塊鏈表保存,即時分配和釋放
  • 小于等于池尺寸的定義為小內存塊,直接從預先分配的內存塊中提取,不夠就擴充池中的內存,在生命周期內對小塊內存不做釋放,直到最后統一銷毀。

圖片

內存池大小, 以及內存對齊的宏定義

圖片

#define MP_ALIGNMENT       		32
#define MP_PAGE_SIZE			4096
#define MP_MAX_ALLOC_FROM_POOL	(MP_PAGE_SIZE-1)

#define mp_align_ptr(p, alignment) (void *)((((size_t)p)+(alignment-1)) & ~(alignment-1))
//分配內存起點對齊

結構定義以及圖解分析

typedef struct mp_large_s {
    struct mp_large_s* next;
    void* alloc;//data區
} mp_large_s;

typedef struct mp_node_s {
    unsigned char* last;//下一次內存分配的起點
    unsigned char* end;//當前內存塊末尾
    size_t failed;//當前內存塊分配失敗的次數
    struct mp_node_s* next;
} mp_node_s;

typedef struct mp_pool_s {
    mp_large_s* large;//指向大塊內存起點
    mp_node_s* current;//指向當前可分配的小內存塊起點
    int max;//小塊最大內存
    mp_node_s head[0];//存儲地址, 不占據內存,變長結構體技巧
    //存儲首塊小內存塊head地址
} mp_pool_s;

mp_pool_s 內存池結構

  1. large 指向第一個大塊
  2. current 指向當前可分配的小塊
  3. head 始終指向第一塊小塊

mp_node_s 小塊內存結構

  1. last 下一次內存分配的起點, 本次內存分配的終點
  2. end 塊內存末尾
  3. failed 當前內存塊申請內存的失敗次數, nginx采取的方式是失敗次數達到一定程度就更換current,current是開始嘗試分配的內存塊, 也就是說失敗達到一定次數, 就不再申請這個內存塊了.

mp_large_s 大塊內存塊

  1. 正常的申請, 然后使用鏈表連接管理起來.
  2. alloc 內存塊, 分配內存塊

函數原型以及功能敘述

//函數申明
mp_pool_s *mp_create_pool(size_t size);//創建內存池
void mp_destory_pool( mp_pool_s *pool);//銷毀內存池
void *mp_alloc(mp_pool_s *pool, size_t size);
//從內存池中申請并且進行字節對齊
void *mp_nalloc(mp_pool_s *pool, size_t size);
//從內存池中申請不進行字節對齊
void *mp_calloc(mp_pool_s *pool, size_t size);
//模擬calloc
void mp_free(mp_pool_s *pool, void *p);
void mp_reset_pool(struct mp_pool_s *pool);
//重置內存池
static void *mp_alloc_block(struct mp_pool_s *pool, size_t size);
//申請小塊內存
static void *mp_alloc_large(struct mp_pool_s *pool, size_t size);
//申請大塊內存

對應nginx函數原型

圖片

圖片

重點函數分塊細節刨析

mp_create_pool: 創建線程池

第一塊內存: 大小設置為 size + sizeof(node) + sizeof(pool) ?

mp_node_s head[0] 啥意思?

mp_pool_s* mp_create_pool(size_t size) {
    struct mp_pool_s *p = NULL;
	int ret = posix_memalign((void **)&p, MP_ALIGNMENT, size + sizeof(mp_pool_s) + sizeof(mp_node_s));
	if (ret) {
		return NULL;
	}
	//內存池小塊的大小限制
	p- >max = (size < MP_MAX_ALLOC_FROM_POOL) ? size : MP_MAX_ALLOC_FROM_POOL;
	p- >current = p- >head;//第一塊為當前塊
	p- >large = NULL;

	p- >head- >last = (unsigned char *)p + sizeof( mp_pool_s) + sizeof(mp_node_s);
	p- >head- >end = p- >head- >last + size;
	p- >head- >failed = 0;

	return p;
}

看完了代碼來回答一下問題

  • 為了盡可能地避免內存碎片地產生, 小內存地申請, 于是我采取地方式是將 memory pool內存池也放入到首塊內存中地方式. 同時所有地node結點信息也都統一存儲在每一個內存塊中.
  • head[0] : 是一種常用于變長結構體地技巧, 不占用內存, 僅僅只是表示一個地址信息, 存儲head node 的地址.

mp_alloc 帶字節對齊的內存申請

首先按照size大小選擇內存分配方式, 小于等于線程池小塊最大大小限制就從已有小塊中申請, 小塊不足就調用mp_alloc_block創建新的小塊 否則就調用 mp_alloc_large 申請創建一個大塊內存

mp_align_ptr 用于字節對齊

void *mp_alloc(mp_pool_s *pool, size_t size) {
    mp_node_s* p = NULL;
    unsigned char* m = NULL;
    if (size <= MP_MAX_ALLOC_FROM_POOL) {//從小塊中分配
        p = pool- >current;
        do {//循環嘗試從現有小塊中申請
            m = mp_align_ptr(p- >last, MP_ALIGNMENT);
            if ((size_t)(p- >end - m) >= size) {
                p- >last = m + size;
                return m;  
            }
            p = p- >next;
        } while (p);
        //說明小塊中都分配失敗了, 于是從新申請一個小塊
        return mp_alloc_block(pool, size);
    }
    //從大塊中分配
    return mp_alloc_large(pool, size);
}

mp_alloc_block 申請創建新的小塊內存

psize 大小等于mp_node_s結點內存大小 + 實際可用內存塊大小

搞清楚內存塊組成:結點信息 + 實際可用內存塊

返回的內存是實際可用內存的起始地址

//申請小塊內存
void *mp_alloc_block(struct mp_pool_s *pool, size_t size) {
    unsigned char* m = NULL;
    size_t psize = 0;//內存池每一塊的大小
    psize = (size_t)((unsigned char*)pool- >head- >end - (unsigned char*)pool- >head);
    int ret = posix_memalign((void**)&m, MP_ALIGNMENT, psize);
    if (ret) return NULL;
    //此時已經分配出來一個新的塊了
    mp_node_s* new_node, *p, *current;
    new_node = (mp_node_s*)m;

    new_node- >end = m + psize;
    new_node- >failed = 0;
    new_node- >next = NULL;

    m += sizeof(mp_node_s);//跳過node
    //對于m進行地址起點內存對齊
    m = mp_align_ptr(m, MP_ALIGNMENT);
    new_node- >last = m + size;

    current = pool- >current;
    //循環尋找新的可分配內存塊起點current
    for (p = current; p- >next; p = p- >next) {
        if (p- >failed++ > 4) {
            current = p- >next;
        }
    }
    //將new_node連接到最后一塊內存上, 并且嘗試跟新pool- >current
    pool- >current = current ? current : new_node;
    p- >next = new_node;
    return m;
}

mp_alloc_large 申請創建新的大塊內存

大塊內存參考nginx_pool 采取采取的是malloc分配

先分配出來所需大塊內存. 在pool的large鏈表中尋找是否存在空閑的alloc. 存在則將內存掛在上面返回. 尋找5次還沒有找到就另外申請一個新的large結點掛載內存, 鏈接到large list中管理

mp_large_s* node 是從內存池中分配的, 也就是從小塊中分配的 why? 減少內存碎片, 將大塊的node信息放入小塊內存中,避免小內存的申請, 減少內存碎片

留疑? 空閑的alloc從何而來?

void *mp_alloc_large(struct mp_pool_s *pool, size_t size) {
    void* p = malloc(size);
    if (p == NULL) return NULL;
    mp_large_s* l = NULL;
    size_t cnt = 0;

    for (l = pool- >large; l; l = l- >next) {
        if (l- >alloc) {
            l- >alloc = p;
            return p;
        }
        if (cnt++ > 3) {
            break;//為了提高效率, 檢查前5個塊, 沒有空閑alloc就從新申請large
        }
    }
 	l = mp_alloc(pool, sizeof(struct mp_large_s));
	if (l == NULL) {
		free(p);
		return NULL;
	}

    l- >alloc = p;
    l- >next = pool- >large;
    pool- >large = l;
    return p;
}

空閑的alloc是被free掉了空閑出來的. 雖然nginx采取的是小塊不單獨回收, 最后統一回收, 因為小塊的回收非常難以控制, 不清楚何時可以回收. 但是對于大塊nginx提供了free回收接口.

mp_free_large 回收大塊內存資源

void mp_free_large(mp_pool_s *pool, void *p) {
    mp_large_s* l = NULL;
    for (l = pool- >large; l; l = l- >next) {
        if (p == l- >alloc) {
            free(l- >alloc);

            l- >alloc = NULL;
            return ;
        }
    }

}

整體代碼附下

#ifndef _MPOOL_H_
#define _MPOOL_H_

#include < stdlib.h >
#include < stdio.h >
#include < string.h >
#include < unistd.h >
#include < fcntl.h >

#define MP_ALIGNMENT       		32
#define MP_PAGE_SIZE			4096
#define MP_MAX_ALLOC_FROM_POOL	(MP_PAGE_SIZE-1)

#define mp_align_ptr(p, alignment) (void *)((((size_t)p)+(alignment-1)) & ~(alignment-1))
//內存起點對齊

typedef struct mp_large_s {
    struct mp_large_s* next;
    void* alloc;//data區
} mp_large_s;

typedef struct mp_node_s {
    unsigned char* last;//下一次內存分配的起點
    unsigned char* end;//當前內存塊末尾
    size_t failed;//當前內存塊分配失敗的次數
    struct mp_node_s* next;
} mp_node_s;

typedef struct mp_pool_s {
    mp_large_s* large;//指向大塊內存起點
    mp_node_s* current;//指向當前可分配的小內存塊起點
    int max;//小塊最大內存
    mp_node_s head[0];//存儲地址, 不占據內存,變長結構體技巧
    //存儲首塊小內存塊head地址
} mp_pool_s;

//函數申明
mp_pool_s *mp_create_pool(size_t size);//創建內存池
void mp_destory_pool( mp_pool_s *pool);//銷毀內存池
void *mp_alloc(mp_pool_s *pool, size_t size);
//從內存池中申請并且進行字節對齊
void *mp_nalloc(mp_pool_s *pool, size_t size);
//從內存池中申請不進行字節對齊
void *mp_calloc(mp_pool_s *pool, size_t size);
//模擬calloc
void mp_free(mp_pool_s *pool, void *p);
void mp_reset_pool(struct mp_pool_s *pool);
//重置內存池
static void *mp_alloc_block(struct mp_pool_s *pool, size_t size);
//申請小塊內存
static void *mp_alloc_large(struct mp_pool_s *pool, size_t size);
//申請大塊內存

mp_pool_s* mp_create_pool(size_t size) {
    struct mp_pool_s *p = NULL;
	int ret = posix_memalign((void **)&p, MP_ALIGNMENT, size + sizeof(mp_pool_s) + sizeof(mp_node_s));
	if (ret) {
		return NULL;
	}
	//內存池小塊的大小限制
	p- >max = (size < MP_MAX_ALLOC_FROM_POOL) ? size : MP_MAX_ALLOC_FROM_POOL;
	p- >current = p- >head;//第一塊為當前塊
	p- >large = NULL;

	p- >head- >last = (unsigned char *)p + sizeof( mp_pool_s) + sizeof(mp_node_s);
	p- >head- >end = p- >head- >last + size;
	p- >head- >failed = 0;

	return p;
}

void mp_destory_pool( mp_pool_s *pool) {
    //先銷毀大塊
    mp_large_s* l = NULL;
    mp_node_s* p = pool- >head- >next, *q = NULL;
    for (l = pool- >large; l; l = l- >next) {
        if (l- >alloc) {
            free(l- >alloc);
            l- >alloc = NULL;
        }
    }
    //然后銷毀小塊內存
    while (p) {
        q = p- >next;
        free(p);
        p = q;
    }
    free(pool);
}



//申請小塊內存
void *mp_alloc_block(struct mp_pool_s *pool, size_t size) {
    unsigned char* m = NULL;
    size_t psize = 0;//內存池每一塊的大小
    psize = (size_t)((unsigned char*)pool- >head- >end - (unsigned char*)pool- >head);
    int ret = posix_memalign((void**)&m, MP_ALIGNMENT, psize);
    if (ret) return NULL;
    //此時已經分配出來一個新的塊了
    mp_node_s* new_node, *p, *current;
    new_node = (mp_node_s*)m;

    new_node- >end = m + psize;
    new_node- >failed = 0;
    new_node- >next = NULL;

    m += sizeof(mp_node_s);//跳過node
    //對于m進行地址起點內存對齊
    m = mp_align_ptr(m, MP_ALIGNMENT);
    new_node- >last = m + size;
    current = pool- >current;
    for (p = current; p- >next; p = p- >next) {
        if (p- >failed++ > 4) {
            current = p- >next;
        }
    }
    //將new_node連接到最后一塊內存上, 并且嘗試跟新pool- >current
    pool- >current = current ? current : new_node;
    p- >next = new_node;
    return m;
}

//申請大塊內存
void *mp_alloc_large(struct mp_pool_s *pool, size_t size) {
    void* p = malloc(size);
    if (p == NULL) return NULL;
    mp_large_s* l = NULL;
    size_t cnt = 0;

    for (l = pool- >large; l; l = l- >next) {
        if (l- >alloc) {
            l- >alloc = p;
            return p;
        }
        if (cnt++ > 3) {
            break;//為了提高效率, 檢查前5個塊, 沒有空閑alloc就從新申請large
        }
    }
 	l = mp_alloc(pool, sizeof(struct mp_large_s));
	if (l == NULL) {
		free(p);
		return NULL;
	}

    l- >alloc = p;
    l- >next = pool- >large;
    pool- >large = l;
    return p;
}


//帶有字節對齊的申請
void *mp_alloc(mp_pool_s *pool, size_t size) {
    mp_node_s* p = NULL;
    unsigned char* m = NULL;
    if (size < MP_MAX_ALLOC_FROM_POOL) {//從小塊中分配
        p = pool- >current;
        do {
            m = mp_align_ptr(p- >last, MP_ALIGNMENT);
            if ((size_t)(p- >end - m) >= size) {
                p- >last = m + size;
                return m;  
            }
            p = p- >next;
        } while (p);
        //說明小塊中都分配失敗了, 于是從新申請一個小塊
        return mp_alloc_block(pool, size);
    }
    //從大塊中分配
    return mp_alloc_large(pool, size);
}



//不帶字節對齊的從內存池中申請內存
void *mp_nalloc(mp_pool_s *pool, size_t size) {
    mp_node_s* p = NULL;
    unsigned char* m = NULL;
    if (size < MP_MAX_ALLOC_FROM_POOL) {//從小塊中分配
        p = pool- >current;
        do {
            m = p- >last;
            if ((size_t)(p- >end - m) >= size) {
                p- >last = m + size;
                return m;  
            }
            p = p- >next;
        } while (p);
        //說明小塊中都分配失敗了, 于是從新申請一個小塊
        return mp_alloc_block(pool, size);
    }
    //從大塊中分配
    return mp_alloc_large(pool, size);
}


void *mp_calloc(struct mp_pool_s *pool, size_t size) {

	void *p = mp_alloc(pool, size);
	if (p) {
		memset(p, 0, size);
	}

	return p;
	
}

void mp_free(mp_pool_s *pool, void *p) {
    mp_large_s* l = NULL;
    for (l = pool- >large; l; l = l- >next) {
        if (p == l- >alloc) {
            free(l- >alloc);

            l- >alloc = NULL;
            return ;
        }
    }

}

#endif
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內存
    +關注

    關注

    8

    文章

    3103

    瀏覽量

    74919
  • JAVA
    +關注

    關注

    20

    文章

    2983

    瀏覽量

    106645
  • 程序
    +關注

    關注

    117

    文章

    3817

    瀏覽量

    82255
  • 函數
    +關注

    關注

    3

    文章

    4365

    瀏覽量

    63965
  • nginx
    +關注

    關注

    0

    文章

    163

    瀏覽量

    12461
收藏 人收藏

    評論

    相關推薦
    熱點推薦

    C++內存的設計與實現

    內存化技術中的一種形式。通常我們在編寫程序的時候回使用 new delete 這些關鍵字來向操作系統申請內存,而這樣造成的后果就是每次申請內存
    發表于 09-23 10:22 ?1094次閱讀

    內存可以調節內存的大小嗎

    嵌入式–內存直接上代碼,自己體會。嵌入式設備,一般keil提供的堆很小,一般都不使用。使用內存,自己可以調節內存大小。頭文件 mallo
    發表于 12-17 07:00

    內存的概念和實現原理概述

    { //一:內存的概念和實現原理概述//malloc:內存浪費,頻繁分配小塊內存,則浪費更加顯得明顯//“內存
    發表于 12-17 06:44

    關于RT-Thread內存管理的內存簡析

    這篇文章繼續介紹 RT-Thread 內存管理剩下的部分——內存。為何引入內存?內存堆雖然方
    發表于 04-06 17:02

    RT-Thread內存管理之內存實現分析

    適合它們的高效率的內存分配算法,就將變得復雜化。RT-Thread 操作系統在內存管理上,根據上層應用及系統資源的不同,有針對性地提供了不同的內存分配管理算法??傮w上可分為兩類:內存
    發表于 10-17 15:06

    Linux 內存源碼淺析

    內存需求時還是從公共的內存中直接分配,這樣的做法雖然有點霸占內存的嫌疑,但是可以從根本上保證關鍵應用在內存緊張時申請內存仍然能夠成功。下面
    發表于 04-02 14:32 ?336次閱讀

    LibTorch-based推理引擎優化內存使用和線程

    LibTorch-based推理引擎優化內存使用和線程
    的頭像 發表于 08-31 14:27 ?1546次閱讀
    LibTorch-based推理引擎優化<b class='flag-5'>內存</b>使用和線程<b class='flag-5'>池</b>

    什么是內存

    1什么是內存 1.1化技術 所謂“化技術”,就是程序先向系統申請過量的資源,然后自己管理,以備不時之需。之所以要申請過 量的資源,是因為每次申請該資源都有較大的開銷,不如提前申請
    的頭像 發表于 11-08 16:26 ?1222次閱讀
    什么是<b class='flag-5'>內存</b><b class='flag-5'>池</b>

    高并發內存項目實現

    本項目實現了一個高并發內存,參考了Google的開源項目tcmalloc實現的簡易版;其功能就是實現高效的多線程內存管理。由功能可知,高并發指的是高效的多線程,而內存
    的頭像 發表于 11-09 11:16 ?925次閱讀
    高并發<b class='flag-5'>內存</b><b class='flag-5'>池</b>項目實現

    了解連接、線程內存、異步請求

    可被重復使用像常見的線程內存、連接、對象都具有以上的共同特點。 連接 什么是數據庫連
    的頭像 發表于 11-09 14:44 ?1720次閱讀
    了解連接<b class='flag-5'>池</b>、線程<b class='flag-5'>池</b>、<b class='flag-5'>內存</b><b class='flag-5'>池</b>、異步請求<b class='flag-5'>池</b>

    如何實現一個高性能內存

    寫在前面 本文的內存代碼是改編自Nginx內存源碼,思路幾乎一樣。由于
    的頭像 發表于 11-10 11:11 ?884次閱讀
    如何實現一個高性能<b class='flag-5'>內存</b><b class='flag-5'>池</b>

    內存的使用場景

    為什么要用內存 為什么要用內存?首先,在7 * 24h的服務器中如果不使用內存,而使用ma
    的頭像 發表于 11-10 17:19 ?875次閱讀
    <b class='flag-5'>內存</b><b class='flag-5'>池</b>的使用場景

    Nginx目錄結構有哪些

    很多,例如:新浪、網易、 騰訊等。 為什么要用Nginx? 跨平臺、配置簡單、方向代理、高并發連接:處理2-3萬并發連接數,官方監測能支持5萬并發,內存消耗?。洪_啟10個nginx才占150M
    的頭像 發表于 11-11 11:27 ?832次閱讀
    <b class='flag-5'>Nginx</b>目錄結構有哪些

    內存主要解決的問題

    內存的定義 1.化技術 是在計算機技術中經常使用的一種設計模式,其內涵在于:將程序中需要經常使用的核心資源 先申請出來,放到一個池內,由程序自己管理,這樣可以提高資源的使用效率
    的頭像 發表于 11-13 15:23 ?970次閱讀
    <b class='flag-5'>內存</b><b class='flag-5'>池</b>主要解決的問題

    Nginx服務優化教程

    隱藏Nginx版本號,避免安全漏洞泄漏:修改配置文件法;修改源碼
    的頭像 發表于 03-12 15:57 ?395次閱讀
    <b class='flag-5'>Nginx</b>服務優化教程
    主站蜘蛛池模板: 亚洲三区视频 | 中文字幕一区二区三区 精品 | 影视精品网站入口 | 深夜视频在线免费 | 国产91小视频在线观看 | 亚洲午夜精品久久久久久人妖 | 操一操日一日 | 一级片免费观看视频 | 亚洲成成品网站有线 | 男女艹逼软件 | 四虎影院视频在线观看 | 免费观看老外特级毛片 | 91中文字幕在线视频 | 欧美一级精品高清在线观看 | 狠狠色成人综合首页 | 色噜噜亚洲男人的天堂 | 国产午夜久久影院 | 99久久99久久久99精品齐 | 天堂网在线观看 | 国产性较精品视频免费 | 拍拍拍无挡视频免费全程1000 | 国产三级一区 | 自拍偷拍综合网 | 中文字幕二区三区 | 亚洲欧洲第一页 | 亚洲视频一区二区三区 | 免费久久精品国产片香蕉 | 国产免费久久精品99久久 | 天天爱天天色 | www.瑟瑟| 在线观看一区二区三区视频 | 色色色色色色色色色色色色 | 天天躁日日躁狠狠躁中文字幕老牛 | 无毒不卡在线观看 | 久久精品免费在线观看 | 日本aaaa毛片在线看 | 羞羞答答xxdd影院欧美 | 天天拍天天色 | 中文天堂最新版www 中文天堂最新版在线精品 中文天堂最新版在线中文 中文天堂最新版资源新版天堂资源 | 免费看曰批女人爽的视频网址 | 人人做人人澡人人人爽 |