ProgramingTip

C에서 동적으로 할당 된 메모리의 크기 결정

bestdevel 2021. 1. 10. 22:56
반응형

C에서 동적으로 할당 된 메모리의 크기 결정


C에서 동적으로 할당 된 메모리의 크기를 알아내는 방법이 있습니까?

예를 들어,

char* p = malloc (100);

관련된 메모리의 크기를 알아내는 방법이 p있습니까?


때 때 comp.lang.c 자주하는 질문 목록 · 질문 7.27 -

Q. malloc할당 된 블록의 크기를 확인하기 위해 패키지를 쿼리 할 수 있습니까?

A. 안타깝게도 표준 또는 추천 방법이 없습니다. (일부 컴파일러는 비표준 확장을 제공합니다.) 필요한 경우 직접 추적해야합니다. (질문 7.28 도 참조하십시오 .)


이 정보를 찾는 표준 방법은 없습니다. 그러나 일부 구현 msize에서는 이와 같은 기능을 제공합니다 . 예를 들면 :

하지만 malloc은 요청 된 최소 크기를 할당 할 구현 메모리에 대한 msize 변형이 생성 된 크기를 반환하거나 힙에 할당해야합니다.


C의 사고 방식은 프로그래머에게 작업의 본질을 바꾸는 추상화를 제공하는 것이 아니라 작업에 도움이되는 도구를 제공하는 것입니다. C는 또한 성능 제한을 강화하여 발생하는 경우를 더 안전하게 만드는 것을 방지합니다.

메모리 영역에서 수행 할 수있는 특정 작업에는 영역 시작 위치만이 필요합니다. 이러한 작업에는 널 (null)로 끝나는 문자열 작업 ,-domain 의보기 처음 N 바이트 조작 (영역이 적어도 이만큼 큰 것으로 알려진 경우) 등이 포함됩니다.

C가 자동으로 수행 할 작업을 수행 할 수 있습니다.

많은 라이브러리 함수 (예 fread():)는 영역의 시작에 대한 포인터 와이 영역의 크기가 필요합니다. 영역의 크기가 필요한 경우를 추적해야합니다.

예, malloc () 구현은 일반적으로 영역의 크기를 추적하지만 간접적으로 수행하거나 일부 값으로 반올림하거나 아예 유지하지 않을 수 있습니다. 이를 지원하지만,이 방법으로 크기를 찾는 것이 바로 추적하는 것에 느릴 수 있습니다.

각 지역의 크기를 아는 데이터 구조가 필요한 경우 C가 대신 할 수 있습니다. 영역의 크기와 영역에 대한 포인터를 추적하는 것을 사용하십시오.


아니요, C 런타임 라이브러리는 기능을 제공하지 않습니다.

일부 라이브러리는이 정보를 사용할 수있는 플랫폼 또는 특정 함수를 제공 할 수 있습니다. 일반적 으로이 정보를 추적하는 방법은 다른 정수 변수에 있습니다.


주소와 크기를 저장하기 위해 태그가 지정된 포인터를 만드는 가장 좋은 방법은 다음과 가변합니다. 모든 포인터는 여전히 예상대로 작동합니다.

도난 : https://stackoverflow.com/a/35326444/638848

또한 malloc에 ​​대한 래퍼를 구현하고 malloc이 반환하는 포인터 태그 (할당 크기 및 기타 메타 정보 등)를 자유롭게 사용할 수 있습니다. 이것은 실제로 C ++ 컴파일러가 가상 클래스에 대한 참조로 객체에 태그를 지정하는 방법입니다. 다음은 작동하는 한 가지 예입니다.

#include <stdlib.h>
#include <stdio.h>

void * my_malloc(size_t s) 
{
  size_t * ret = malloc(sizeof(size_t) + s);
  *ret = s;
  return &ret[1];
}

void my_free(void * ptr) 
{
  free( (size_t*)ptr - 1);
}

size_t allocated_size(void * ptr) 
{
  return ((size_t*)ptr)[-1];
}

int main(int argc, const char ** argv) {
  int * array = my_malloc(sizeof(int) * 3);
  printf("%u\n", allocated_size(array));
  my_free(array);
  return 0;
}

크기와 포인터가있는 구조에 비해이 방법의 장점

 struct pointer
 {
   size_t size;
   void *p;
 };

malloc과 무료 통화 만 교체하면됩니다. 다른 모든 포인터 작업에는 리팩토링이 필요하지 않습니다.


다른 모든 사람들이 이미 말했듯이 : 없습니다.

또한 여기에서는 모든 공급 업체별 기능을 항상 피할 것입니다. 왜냐하면 일반적으로 잘못하고 있다는 것을 알게됩니다. 크기를 저장하거나 전혀 알 필요가 없습니다. 벤더 함수를 사용하는 것은 가장 빠른 방법입니다.


나는 이것이 구현에 따라 기대합니다.
헤더 데이터 구조를 얻은 경우 포인터에서 다시 캐스팅하여 크기를 얻을 수 있습니다.


그것은 불가능한 말하는 모든 사람은 기술적으로 말하는 것입니다.

엔지니어링상의 재구성 malloc 서브 시스템에 의존하여 할당 된 블록의 크기를 정확하게 알려주는 좋지 않습니다. 이를 확신하기 위해 여러 메모리 할당을 사용 하여하여 다수의 응용 프로그램 을 구축하고 상상해 malloc. 한 부분에서는 원시 libc를 사용 operator new하고 다른 부분에서는 C ++를 사용 하고 있으며 특정 Windows API를 사용할 수 있습니다. 그래서 당신은 온갖 종류의 void*비행을하고 있습니다. 포인터의 값에서 어떤 힙에서 왔는지 알 수없는 기능 하나에서 작동하는 함수를 작성하는 void*것은 불가능합니다.

따라서 프로그램의 각 포인터를 포인터의 출처 (및 포인터를 반환하는 위치)를 사용하여 래핑 할 수 있습니다. 예를 들어, C ++에서 우리는 std::unique_ptr<void>( operator delete'd std::unique_ptr<void, D>가 필요한 포인터의 경우 ) 또는 (다른 똑같이 통해 반환되어야하는 포인터의 경우 ) 이를 호출합니다 D. 같은 C 같은 일을 할 수 있습니다. 어쨌든 더 큰 걱정할로 포인터를 래핑 하면 작은 단계에 struct SizedPtr { void *ptr; size_t size; }불고기 할당 크기에 대해 다시는 필요가 없습니다.

하나.

있습니다 또한 당신이 합법적으로 할당의 실제 기본 크기를 알아야 할 수 있습니다 좋은 이유는. 예를 들어, 프로그래머 가 사용하고 있다고 생각한 메모리 양뿐만 아니라 각 하위 시스템에서 사용 하는 실제 메모리 양을보고하는 앱용 프로파일 링 도구를 작성하고있을 수 있습니다 . 각 10 바이트 할당이 비밀리에 16 바이트를 사용하고 권한 알아두면 좋습니다! (물론이 방식으로 측정하지 않는 다른 오버 헤드도있을 것입니다.하지만 해당 작업을 위한 다른 도구가 아직 있습니다 .) 아니면 플랫폼에서 의 동작을 조사하고 가능성이 있습니다 . 또는 조기 할당을 방지하기 위해 증가하는 할당의 용량을 "반올림"하고 싶을 수도 있습니다.realloc재 할당. 예 :

SizedPtr round_up(void *p) {
    size_t sz = portable_ish_malloced_size(p);
    void *q = realloc(p, sz);  // for sanitizer-cleanliness
    assert(q != NULL && portable_ish_malloced_size(q) == sz);
    return (SizedPtr){q, sz};
}
bool reserve(VectorOfChar *v, size_t newcap) {
    if (v->sizedptr.size >= newcap) return true;
    char *newdata = realloc(v->sizedptr.ptr, newcap);
    if (newdata == NULL) return false;
    v->sizedptr = round_up(newdata);
    return true;
}

사용자 정의 힙이 아니라 객체 중간을 가리 키지 않는 libc malloc에서 직접 반환 된 null이 아닌 포인터 뒤의 할당 크기를 얻을 수있는 다음과 같은 OS 별 API를 사용할 수 있습니다. 편의를 위해 "휴대용"래퍼 기능으로 묶었습니다. 이 코드가 작동하지 않는 일반적인 시스템을 찾으면 댓글을 애무 주시면 수정하겠습니다!

#if defined(__linux__)
// https://linux.die.net/man/3/malloc_usable_size
#include <malloc.h>
size_t portable_ish_malloced_size(const void *p) {
    return malloc_usable_size((void*)p);
}
#elif defined(__APPLE__)
// https://www.unix.com/man-page/osx/3/malloc_size/
#include <malloc/malloc.h>
size_t portable_ish_malloced_size(const void *p) {
    return malloc_size(p);
}
#elif defined(_WIN32)
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/msize
#include <malloc.h>
size_t portable_ish_malloced_size(const void *p) {
    return _msize((void *)p);
}
#else
#error "oops, I don't know this system"
#endif

#include <stdio.h>
#include <stdlib.h>  // for malloc itself

int main() {
    void *p = malloc(42);
    size_t true_length = portable_ish_malloced_size(p);
    printf("%zu\n", true_length);
}

테스트 대상 :

  • Visual Studio, Win64 — _msize
  • GCC / Clang, glibc, Linux — malloc_usable_size
  • Clang, libc, Mac OS X — malloc_size
  • Clang, jemalloc, Mac OS X — 실제로 작동하지만 믿을 수 없습니다 (제말 록 malloc과 내장 libc를 자동으로 혼합 malloc_size)
  • Linux 에서 jemalloc 과 잘 작동해야합니다.
  • 없이 컴파일하면 Linux 에서 dlmalloc 과 잘 작동합니다.USE_DL_PREFIX
  • 모든 곳 에서 tcmalloc 과 잘 작동해야합니다.

malloc을 사용하면 크기를 얻을 수 없습니다.

반면에 Windows 힙 함수 와 같이 OS API를 사용하여 동적으로 메모리를 할당 하면 그렇게 할 수 있습니다.


이제 나는 이것이 당신의 특정 질문에 대한 답이 아니라는 것을 알고 있지만, 상자 밖에서 생각하면 ... 아마 당신이 알 필요가 없을 것입니다. Ok, ok, no 나는 당신이 나쁘거나 비 정통적인 구현을 가지고 있다는 것을 의미하지는 않습니다. 할당 된 메모리에서이 경우이 솔루션이 더 좋을 수 있습니다. 너무 많은 오버 헤드를 제공해서는 안되며 실제로 처리중인 경우 "적합"문제를 해결할 것입니다.

if ( p != (tmp = realloc(p, required_size)) ) p = tmp;

또는 이전 내용을 유지해야하는 경우 :

if ( p != (tmp = realloc(p, required_size)) ) memcpy(tmp, p = tmp, required_size);

물론 다음을 사용할 수 있습니다.

p = realloc(p, required_size);

그리고 그것으로 끝납니다.


이 코드는 대부분의 Windows 설치에서 작동합니다.

template <class T>
int get_allocated_bytes(T* ptr)
{
 return *((int*)ptr-4);
}

template <class T>
int get_allocated_elements(T* ptr)
{
 return get_allocated_bytes(ptr)/sizeof(T);
}

코드의 작은 업데이트가 작동 할 수 있습니다.

void* inc = (void*) (++p)
size=p-inc;

그러나 이것은와 관련, 메모리 즉, 1을 발생합니다 p이 경우는 char*. 그렇다면 int*결과는 4가됩니다.

총 할당량을 알 수있는 방법은 없습니다.


Quuxplusone은 다음과 같이 썼습니다. "포인터의 값에서 어떤 힙에서 왔는지 알 수 없다면 이러한 void *에 대해 작동 할 수있는 함수를 작성하는 것은 불가능합니다." C " 에서 동적으로 할당 된 메모리 크기 결정

실제로 Windows에서 _msize는 포인터 값에서 할당 된 메모리 크기를 제공합니다. 주소에 할당 된 메모리가 없으면 오류가 발생합니다.

int main()
{
    char* ptr1 = NULL, * ptr2 = NULL;
    size_t bsz;    
    ptr1 = (char*)malloc(10);
    ptr2 = ptr1;
    bsz = _msize(ptr2);
    ptr1++;
    //bsz = _msize(ptr1);   /* error */
    free(ptr2);

    return 0;
}

#define 컬렉션에 감사드립니다. 다음은 매크로 버전입니다.

#define MALLOC(bsz) malloc(bsz)
#define FREE(ptr) do { free(ptr); ptr = NULL; } while(0)
#ifdef __linux__
#include <malloc.h>
#define MSIZE(ptr) malloc_usable_size((void*)ptr)
#elif defined __APPLE__
#include <malloc/malloc.h>
#define MSIZE(ptr) malloc_size(const void *ptr)
#elif defined _WIN32
#include <malloc.h>
#define MSIZE(ptr) _msize(ptr)
#else
#error "unknown system"
#endif

참조 URL : https://stackoverflow.com/questions/1281686/determine-size-of-dynamically-allocated-memory-in-c

반응형