Leveldb 소스 코드 분석 2.1- 메모리 풀 구현의 핵심 디자인

Leveldb 소스 코드 분석 2.1- 메모리 풀 구현의 핵심 디자인

소개

보다 합리적으로 메모리를 사용하기 위해 leveldb에서 커스텀 메모리 풀을 구현합니다.

1 데이터 구조

Leveldb의 메모리 풀 구현 클래스는 Arena이고 핵심 데이터 필드는 다음과 같습니다.
여기에 사진 설명 삽입
먼저, 할당 된 메모리 블록을 저장하기 위해 blocks_의 벡터 유형을 사용하고, 새로 적용된 메모리에서 사용하지 않는 메모리의 첫 번째 주소를 가리 키려면 alloc_ptr_을 사용합니다. ; use alloc_bytes_remaining_ 새로 적용된 메모리에서 사용되지 않은 메모리의 바이트 크기를 나타냅니다. 특히 memory_usage_는 모든 bock 및 blocks_ 변수가 차지하는 메모리의 합계를 계산합니다.

2 소스 코드 해석

2.1 소스 코드 해석

메모리에 적용 할 수있는 Allocate 및 AllocateAligned 메소드가 있으며 후자는 시작 주소 정렬 기능이 더 많습니다.

  1. AllocateAligned 함수
char* Arena::AllocateAligned(size_t bytes) {
    
    
  //进行最低8字节的对齐
  const int align = (sizeof(void*) > 8) ? sizeof(void*) : 8;
  static_assert((align & (align - 1)) == 0,
                "Pointer size should be a power of 2");
  size_t current_mod = reinterpret_cast<uintptr_t>(alloc_ptr_) & (align - 1);
  size_t slop = (current_mod == 0 ? 0 : align - current_mod);
  size_t needed = bytes + slop;
  char* result;
  if (needed <= alloc_bytes_remaining_) {
    
      //如果最新内存块有空余空间
    result = alloc_ptr_ + slop; //移动对齐补全字节
    alloc_ptr_ += needed; //重置未使用内存指针
    alloc_bytes_remaining_ -= needed; //重置未使用内存大小
  } else {
    
      //如果最新内存块没有空余空间
    result = AllocateFallback(bytes);
  }
  assert((reinterpret_cast<uintptr_t>(result) & (align - 1)) == 0);
  return result;
}
  1. AllocateFallback 함수
char* Arena::AllocateFallback(size_t bytes) {
    
    
  if (bytes > kBlockSize / 4) {
    
    
    // 如果申请内存大小大于1K,那么进入下面,申请bytes大小然后直接使用
    char* result = AllocateNewBlock(bytes);
    return result;
  }

  // 如果申请内存大小大于1K,直接申请4K大内存后,还需要重置alloc_ptr_和alloc_bytes_remaining_
  alloc_ptr_ = AllocateNewBlock(kBlockSize);
  alloc_bytes_remaining_ = kBlockSize;

  char* result = alloc_ptr_;
  alloc_ptr_ += bytes;
  alloc_bytes_remaining_ -= bytes;
  return result;
}
  1. AllocateNewBlock 함수
char* Arena::AllocateNewBlock(size_t block_bytes) {
    
    
  char* result = new char[block_bytes];
  blocks_.push_back(result);
  // 加sizeof(char*)是因为blocks_还占用一个指针大小的存储空间
  memory_usage_.fetch_add(block_bytes + sizeof(char*),
                          std::memory_order_relaxed);
  return result;
}

2.2 문제 발견

Arena 소스 코드를 읽으면 다음 시나리오에서 메모리가 낭비됩니다.

  1. 먼저 AllocateAligned를 호출하여 512Byte 메모리를 신청하면 큰 4K 메모리가 적용되고 나머지 3.5K 메모리를 할당 할 수 있습니다.
  2. 그런 다음 AllocateAligned를 호출하여 512Byte 메모리를 6 번 신청하면 마지막으로 나머지 512Byte 메모리를 할당 할 수 있습니다.
  3. 계속해서 600Byte 메모리를 신청하세요. 이때 새로운 4K 대용량 메모리가 새로 추가됩니다. 이때 alloc_ptr_ 및 alloc_bytes_remaining_은이 4K 새로운 대용량 메모리의 여유 공간을 기록합니다. 이전 4K의 나머지 512 바이트는 낭비 됩니다.

추천

출처blog.csdn.net/fs3296/article/details/108120235