2010-11-26 5 views
2

나는 표준 할당자를 얼마나 많은 메모리를 소비하는지에 대해 "전화 집으로 돌아 가게"할 할당 자로 바꿨다. 이제는 내 코드 중 일부를 살펴보고 왜 그렇게 많은 항목을 할당하고 할당을 해제하는지 궁금해합니다.STL에서 여분의 할당과 마 법적 공간 축소 - rvalue 참조 사용

참조 용으로 코드를 미리 최적화하려고하지 않습니다. 내 총 크기가 꺼져 있는지 확실히 알 필요가 있다는 것을 제외하고는 대부분 궁금합니다. 개체가 C# GC에 사용 중입니다.

void add_file(string filename, string source) { 
    file_source_map.insert(std::pair<const string, string>(std::move(filename), std::move(source))); 
} 

그것은 여섯 번 (48bytes)를 할당하고, 그 다음 네 번 (32 바이트)를 할당 해제 :

이 샘플 기능을 가지고. 쌍이 rvalue이고 문자열을이 필드로 옮겼으므로 확실히 맵은 새로운 노드를 할당하고 더 이상 할당을 트리거하지 않고 임의의 할당을 해제하지 않고도 rvalue 쌍을이 노드로 이동합니다. 파일 이름과 소스 인수도 rvalues에서 가져오고 복사해야합니다. 단지 참고 사항 : 문자열도 할당자가 추적합니다. std :: string은 아니지만 std::basic_string<char, std::char_traits<char>, Allocator<char>>입니다.

참조 용으로, 저는 MSVC에 있습니다.

여기 내 할당 코드이다 : 나는 래퍼 함수를 ​​통해 C에서 # add_file (위 게시)를 호출 할 때

template<typename T> 
class Allocator { 
public : 
    // typedefs 

    typedef T value_type; 
    typedef value_type* pointer; 
    typedef const value_type* const_pointer; 
    typedef value_type& reference; 
    typedef const value_type& const_reference; 
    typedef std::size_t size_type; 
    typedef std::ptrdiff_t difference_type; 

public : 
    // convert an allocator<T> to allocator<U> 

    template<typename U> 
    struct rebind { 
     typedef Allocator<U> other; 
    }; 

public : 
    Parser* parser; 
    inline ~Allocator() {} 
    inline Allocator(Allocator const& other) { 
     parser = other.parser; 
    } 
    inline Allocator(Parser* ptr) 
     : parser(ptr) {} 
    template<typename U> 
    inline Allocator(Allocator<U> const& other) { 
     parser = other.parser; 
    } 

    // address 

    inline pointer address(reference r) { return &r; } 
    inline const_pointer address(const_reference r) { return &r; } 

    // memory allocation 

    inline pointer allocate(size_type cnt, 
     typename std::allocator<void>::const_pointer = 0) { 
      int newsize = cnt * sizeof (T); 
      parser->size += newsize; 
      std::cout << "Allocated " << newsize << "\n"; 
      return reinterpret_cast<pointer>(::operator new(newsize)); 
    } 
    inline void deallocate(pointer p, size_type count) { 
     size_type size = count * sizeof(T); 
     ::operator delete(p); 
     parser->size -= size; 
     std::cout << "Deallocated " << size << "\n"; 
    } 

    // size 

    inline size_type max_size() const { 
     return std::numeric_limits<size_type>::max()/sizeof(T); 
    } 

    // construction/destruction 

    inline void construct(pointer p, const T& t) { new(p) T(t); } 
    inline void destroy(pointer p) { p->~T(); } 

    inline bool operator==(Allocator const& other) { return other.parser == parser; } 
    inline bool operator!=(Allocator const& a) { return !operator==(a); } 
}; 

, 나는 각각의 할당 및 할당 취소하고 콘솔에서 자신의 적절한 크기를 명확하게 볼 수 있고, 즉 4 개의 할당 8 개, 80 개 중 하나가지도에서 나오고 8 개는 2 개 더 할당 된 다음 8 개는 4 개 할당 해제됩니다. 이는 함수에 4 개의 중복 문자열이 있다고 말합니다. 할당 해제가 발생할 이유가 없습니다.

+0

노드를 16 바이트로 맞추는 것을 "알았습니까"? 당신 할당 자 때문인가요? 아마도 문제는 "마법"STL 코드보다는 할당 자 로직에 있습니다. –

+0

@Peter : 할당 자 논리는 매우 간단합니다. count * sizeof (T)를 할당하면 countof * sizeof (T)의 할당을 해제합니다. 할당을 잘못 추적했다면 STL 코드가 가지고있는 것보다 더 많은 메모리가 필요할 때 충돌이 발생하고 할당 해제를 잘못 추적하면 메모리 누수가 발생합니다. – Puppy

+0

@DeadMG : 할당 자의 관련 코드와 16 바이트/노드를 나타내는 코드를 게시하는 것이 좋습니다. –

답변

5

나는 VS 2010에서 코드를 실행, 나는 당신이 볼 수있는 할당이 할당이 _String_val 생성자에서 발행 된 모든 8 바이트로만 비주얼 스튜디오 STL의 디버깅 기능이 있다고 생각 : 릴리스에서

  • (_ITERATOR_DEBUG_LEVEL == 0) , 생성자는 흔하지 않다
  • 디버그 (_ITERATOR_DEBUG_LEVEL != 0)에서는 할당자를 통해 _Container_proxy (크기가 8 인 경우)을 할당합니다.

릴리스 모드에서 코드를 실행하면 맵의 노드 할당이 72 바이트로 떨어지고 8 바이트 할당 및 할당 취소가 사라집니다. 문자열이 올바르게 이동 된 것 같습니다.

+0

분명히, 나는 나의 다중 프로젝트 설정을 잘못 처리했다. 그리고 당신은 완전히 정확하다. See, release 모드에서 시도해 볼 생각이었는데, 내가 체크했을 때, 그것들을 지우지는 않았다. 아마도 저는 제대로 업데이트하지 않았을 것입니다. 이번에는 빌드를 사용할 때 파일의 시간이 변경되지 않았지만 재구성 할 때 변경된 사항이있는 것으로 나타났습니다. 이상한. 그러나 이것은 정답이었습니다. – Puppy