C++메모리 탱크 의 간단 한 실현

8766 단어 C++메모리 탱크
1.메모리 탱크 기초 지식
1.메모리 풀 이란 무엇 인가
1.1 연못 화 기술
지 화 기술 은 컴퓨터 의 디자인 모델 로 주로 프로그램 에서 자주 사용 해 야 하 는 컴퓨터 자원 을 미리 신청 하고 프로그램 이 스스로 관리 하 며 프로그램 이 사용 할 때'지'에서 직접 얻 는 것 을 말한다.프로그램 이 차지 하 는 자원 의 수량 을 확보 할 뿐만 아니 라 자원 의 신청 과 방출 시간 도 줄 일 수 있다.흔히 볼 수 있 는 연못 화 기술 은 메모리 탱크,스 레 드 탱크,연결 탱크 등 이 있다.
1.2 메모리 풀
메모리 탱크 는 동적 메모리 분배 와 관리 기술 의 하나 다.그것 의 핵심 사상 은 메모리 공간 을 미리 신청 하고 효율 적 인 데이터 구조(해시,링크)를 사용 하여 관리 하 는 것 이다.프로그램 이 메모리 가 필요 할 때 메모리 풀 에서 직접 메모리 공급 프로그램 을 분배 하고 똑 같이 사용 이 끝 났 을 때 메모리 풀 에 돌려 주 는 것 이다.이렇게 하면 new/delete,malloc/freee 등 API 신청 과 메모 리 를 직접 사용 하 는 시간 을 줄 이 고 프로그램 운행 효율 을 높 일 수 있다 는 장점 이 있다.이 동시에 프로그램 은 매번 new/delete,malloc/freee 를 직접 사용 하여 메모리 에서 공간 을 신청 하면 메모리 조각 문 제 를 초래 할 수 있 습 니 다.메모리 탱크 는 큰 메모리 에 직접 신청 하면 메모리 조각 을 줄 일 수 있 습 니 다.
2.메모리 탱크 의 역할
2.1 효율 문제
일반적으로 신청 메모 리 는 new/delete,malloc/free 인 터 페 이 스 를 통 해 메모리 의 더미 에서 메모 리 를 직접 신청 하고 방출 도 더미 에 직접 방출 합 니 다.빈번 한 신청 과 석방 은 반드시 많은 시간 을 소모 하여 프로그램의 운행 효율 을 떨 어 뜨 릴 것 이다.
예 를 들 어 모든 링크 의 노드 크기 가 16 바이트 라 고 가정 하면 링크 가 노드 를 자주 삽입 해 야 할 때 빈번 한 메모리 신청 으로 조작 을 해 야 한다.매번 에 더미 에서 16 개의 바이트 를 신청 할 때마다 일정한 시간 을 써 야 하고 메모 리 를 방출 하 는 데 도 시간 이 필요 하 다.메모리 풀 을 사용 하면 우 리 는 메모리 에서'일부 노드'를 직접 신청 할 수 있 습 니 다.프로그램 이 메모리 가 필요 할 때 직접 쌓 아 올 리 지 않 고 미리 신청 한 메모 리 를 프로그램 에 배분 할 수 있 습 니 다.
2.2 메모리 조각
메모리 에서 작은 메모 리 를 자주 신청 하면 메모리 조각 문제 가 발생 할 수 있 습 니 다.메모리 조각 은 내 조각 과 외 조각 두 가지 로 나 뉜 다.
1)바깥 조각
바깥 조각 은 우리 가 흔히 말 하 는 메모리 조각 이다.예 를 들 어 우 리 는 메모리 에서 16 바이트 크기 의 메모 리 를 신청 할 때마다 메모리 에 16 바이트 크기 의 블록 이 많이 존재 합 니 다.이 메모리 가 방출 될 때 메모리 조각 을 만 들 수 있 습 니 다.다음 그림:
메모리 의 남 은 메모리 크기 는 88 바이트 이지 만,우리 가 신청 할 수 있 는 최대 메모리 블록 은 21 바이트 입 니 다.

2)내부 조각
내부 조각 은 이미 분 배 된 메모리 에 존재 하 는 사용 되 지 않 은 작은 메모리 입 니 다.메모리 탱크 기술 은 메모리 가 자 유 롭 지만 내부 파편 문 제 를 일 으 켰 기 때문에 내부 파편 은 불가피 하지만 프로그램의 최 적 화 를 통 해 메모리 내 파편 을 줄 일 수 있다.
예 를 들 어 실제 수 요 는 10byte 의 메모 리 를 신청 하 는 것 입 니 다.고정 메모리 풀 은 메모리 정렬 을 할 수 있 습 니 다.16 바이트 의 메모 리 를 한꺼번에 분 배 했 습 니 다.나머지 6 바이트 는 실제 사용 하지 않 았 습 니 다.이 6 바이트 는 메모리 내 조각 입 니 다.
3.메모리 탱크 기술 의 발전
1)가장 간단 한 메모리 탱크
남 은 메모 리 를 가리 키 는 링크 를 만 듭 니 다.분 배 는 링크 에서 팝 을 되 돌려 주 는 것 입 니 다.풀 어 주 는 것 은 push 를 링크 에 저장 하 는 것 입 니 다.메모리 의 2 차 방출 문 제 를 방지 하기 위해 서 는 병합,표시,보 호 를 잘 해 야 한다.
2)고정 메모리 풀
FreeList 류 를 실현 합 니 다.그 본질은 링크 입 니 다.노드 는 고정 크기 의 메모리 이 고 머리 삽입 과 머리 삭제 방식 으로 메모리 방출 을 신청 합 니 다.모든 고정 메모리 분배 기 에는 두 개의 링크 가 있 습 니 다.OpenList 는 할당 되 지 않 은 남 은 메모리 대상(FreeList 대상)을 저장 하 는 데 사 용 됩 니 다.CloseList 는 분 배 된 메모리 대상 을 저장 하 는 데 사 용 됩 니 다.
메모리 할당 은 IOpenLsit 에서 대상 을 꺼 내 프로그램 에 주 는 것 입 니 다.메모리 방출 은 대상 push 를 CloseList 에 넣 는 것 입 니 다.메모리 가 부족 할 때 OpenList 는 큰 메모리 가 고정된 길이 의 작은 메모리 로 자 르 는 것 을 신청 합 니 다.

3)C++STL 라 이브 러 리 의 메모리 풀
고정 메모리 풀 에 존재 하 는 문 제 는 고정 길이 의 메모리 만 신청 하 는 것 입 니 다.실제 우리 가 신청 해 야 할 메모리 크기 는 고정 에 관 계 없 이 C+STL 라 이브 러 리 에서 해시 표 와 고정 메모리 풀 을 결합 하 는 방식 으로 메모리 풀 을 실현 할 수 있 습 니 다.구체 적 으로 다음 과 같다.
여러 개의 고정 메모리 풀 을 구성 하고 고정된 정렬 수 로 정렬 합 니 다(예 를 들 어 8 바이트 로 정렬 합 니 다).첫 번 째 고정 메모리 풀 의 메모리 대상 크기 는 8 입 니 다(적어도 64 비트 든 32 비트 시스템 에서 다음 포인터 형식 을 저장 할 수 있 도록 보장 해 야 합 니 다).두 번 째 메모리 풀 의 대상 크기 는 16 입 니 다.마지막 메모리 풀 의 대상 크기 는 128 byte 입 니 다.신청 한 메모리 크기 가 128 바이트 가 넘 으 면 2 급 공간 설정 기 를 통 해 신청 합 니 다(메모리 에서 직접 신청 합 니 다).
해시 시 계 를 만들어 서 서로 다른 크기 의 메모리 대상 을 해시 표 에 걸 어 라.다음 그림:

신청 메모리:신청 할 메모리 크기 는 8 바이트 로 index 에 직접 있 습 니 다.  = 0 곳 에서 메모 리 를 분배 합 니 다.물론 신청 한 메모리 가 8 바이트 보다 적 을 때 도 8 바이트 의 메모 리 를 직접 분배 합 니 다.자유list[index]nullptr 일 때 메모리 에서 메모 리 를 신청 하여 고정 크기 로 자 르 고'Free'에 걸 기list[index]위치.
메모리 방출:메모리 대상 크기 에 따라 index 가 해시 표 에 삽 입 된 index 위 치 를 계산 합 니 다.
2.간이 메모리 탱크 원리
1.전체적인 디자인
1.1 메모리 풀 구조
두 개의 링크,RequestMemory 와 Release Memory.
RequestMemory 링크 는 new 나 malloc 를 사용 하여 물리 적 메모리 에서 신청 한 아직 사용 되 지 않 은 메모리 블록 으로 memNode 노드 입 니 다.
Release Memory 링크 는 방출 된 고정 크기 의 메모리 블록 을 사용 하여 저장 합 니 다.

1.2 메모리 신청
  •  먼저 Release Memory 에서 찾 습 니 다.메모리 가 있 으 면 바로 pop 에서 사용 합 니 다
  • Release Memory 가 nullptr 일 때 RequestMemory 에서 찾 습 니 다
  • RequestMemory 의 헤드 노드 는 새로 신청 한 것 을 나타 내 고 메모 리 를 신청 할 때 헤드 노드 에서 찾 아서 헤드 노드 의 useCount 와 sumCount 가 같 는 지 판단 해 야 한다.useCount 가 sumCount 와 같 을 때 이미 다 썼 다 고 표시 하면 물리 적 메모리 에서 신청 해 야 합 니 다.그렇지 않 으 면 표 머리 push 에서 한 조각 을 직접 사용 해 야 합 니 다
  • 4.567917.물리 적 메모리 에 메모 리 를 신청 할 때 신청 한 크기 는 지난번 신청 한 메모리 블록 크기 의 두 배 이 고 신청 한 메모리 블록 push 를 RequestMemory 머리 에 넣 습 니 다.
    1.3 메모리 사용
    메모 리 를 풀 때 방출 할 메모 리 를 Release Memory 의 머리 부분 에 직접 푸 시 하면 됩 니 다.
    2.상세 분석
    2.1 blockNode 구조
    BlockNode 는 새로 신청 한 메모리 블록 을 구조 체 로 관리 하 는 것 을 표시 합 니 다.blockNode 멤버 는 다음 과 같 습 니 다:
  • void* _memory:새로 신청 한 메모리 블록 의 첫 번 째 주 소 를 표시 합 니 다
  • BlockNode * _next:next 노드 를 저장 합 니 다
  • _obbxNum:메모리 블록 대상 의 개수
  • 메모:BlockNode 의 크기 는 매번 지난번 의 두 배 이 고 하나의 질 적 증가 이 므 로 상한 선 을 설정 하여 일정한 크기 에 도달 한 후에 선형 성장 을 해 야 합 니 다.여기에 최대 메모리 블록의 크기 를 100000*sizeof(T)로 정 하고 T 는 신청 한 노드 유형 을 나타 낸다.
    2.2 개체 크기
    여기 서 단일 대상 이 가리 키 는 ReleaseMemory 의 노드 크기 는 사용자 가 신청 한 메모리 크기 sizeof(T)가 sizeof(T*)보다 작 을 때 이 대상 을 ReleaseMemory 에 연결 할 수 있 도록 T*에 따라 배분 해 야 합 니 다.
    3.성능 비교
    각각 malloc/free,new/delete,memPool 신청 과 110000 개의 메모 리 를 사용 합 니 다.시간 은 다음 과 같 습 니 다.

    3.간이 메모리 풀 전체 소스 코드
    
    #include<iostream>
    #include<vector>
    #include<ctime>
    using namespace std;
     
    template<class T>
    class MemPool
    {
    private:
    	//     
    	typedef struct BlockNode
    	{
    		void* _memory;//     
    		BlockNode* _next;//   blockNode
    		size_t _objNum;//        
    		//    ---num         
    		BlockNode(size_t num)
    			:_objNum(num),
    			_next(nullptr)
    		{
    			_memory = malloc(_objNum*_size);
    		}
     
    		~BlockNode()
    		{
    			free(_memory);
    			_memory = nullptr;
    			_next = nullptr;
    			_objNum = 0;
    		}
    	}BlockNode;
    protected:
    	static size_t _size;//       
    	T* _releaseMemory = nullptr;//     
    	BlockNode* _requestMemory;//      
    	size_t _maxNum;//        
    	size_t _useCount;//              
    protected:
    	//         
    	static size_t setSize()
    	{
    		return (sizeof(T) >= sizeof(T*) ? sizeof(T):sizeof(T*));
    	}
    public:
    	MemPool()
    		:_useCount(0),
    		_releaseMemory(nullptr),
    		_maxNum(100000*_size)
    	{
    		//     32 _size     
    		_requestMemory = new BlockNode(32);
    	}
     
    	~MemPool()
    	{
    		BlockNode *cur = _requestMemory;
    		while (cur)
    		{
    			BlockNode* del = cur;
    			cur = cur->_next;
    			delete del;            //     ~BlockNode()
    		}
    	}
     
    	T* New()
    	{
    		//  releaseMemory  
    		if (_releaseMemory)
    		{
    			T* obj = _releaseMemory;
    			_releaseMemory = *((T**)_releaseMemory);//releaseMemory                  
    			return obj;
    		}
    		else
    		{
    			//  requesetMemory         
    			if (_requestMemory->_objNum == _useCount)
    			{
    				//            
    				size_t size = 2 * _useCount >= _maxNum ? _maxNum : 2 * _useCount;
    				BlockNode* newBlock = new BlockNode(size);
     
    				newBlock->_next = _requestMemory;
    				_requestMemory = newBlock;
    				_useCount = 0;
    			}
    			//    ,     
    			T* obj = (T*)((char*)_requestMemory->_memory+_useCount*_size);
     
    			_useCount++;
    			return new(obj)T();//   new        
    		}
    	}
     
    	void Delete(T* obj)
    	{
    		if (obj)
    		{
    			obj->~T();
     
    			*((T**)obj) = _releaseMemory;
    			_releaseMemory = obj;
    		}
    	}
    };
     
    //      ,     
    template<typename T>
    size_t MemPool<T>::_size = MemPool<T>::setSize();
     
    struct TreeNode
    {
    	int _val;
    	TreeNode* _left;
    	TreeNode* _right;
    };
    void test1()
    {
    	MemPool<TreeNode> mp;
     
    	vector<TreeNode*> v;
    	for (int i = 0; i < 10; i++)
    	{
    		TreeNode* mem = mp.New();
    		v.push_back(mem);
    	}
     
    	for (int i = 0; i < 10; i++)
    	{
    		mp.Delete(v[i]);
    	}
    }
    C++메모리 풀 의 간단 한 실현 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 C+메모리 풀 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 바 랍 니 다!

    좋은 웹페이지 즐겨찾기