이렇게 하면 메모리를 해방시킬 수 있을까요?
의 인스턴스를 해방하는 함수struct Foo
이하에 나타냅니다.
void DestroyFoo(Foo* foo)
{
if (foo) free(foo);
}
제 동료가 대신 다음과 같은 제안을 했습니다.
void DestroyFoo(Foo** foo)
{
if (!(*foo)) return;
Foo *tmpFoo = *foo;
*foo = NULL; // prevents future concurrency problems
memset(tmpFoo, 0, sizeof(Foo)); // problems show up immediately if referred to free memory
free(tmpFoo);
}
포인터를 로 설정하는 것을 알 수 있습니다.NULL
해방 후가 더 좋지만, 다음 사항은 잘 모르겠습니다.
포인터를 임시 포인터에 할당해야 합니까?동시성과 공유 메모리 측면에서 도움이 됩니까?
프로그램을 강제로 크래시하거나 적어도 큰 차이가 있는 결과를 출력하기 위해 전체 블록을 0으로 설정하는 것이 정말 좋은 생각입니까?
포인터를 임시 포인터에 할당해야 합니까?동시성과 공유 메모리 측면에서 도움이 됩니까?
동시성이나 공유 메모리와는 관계가 없습니다.그건 무의미해.
프로그램을 강제로 크래시하거나 적어도 큰 차이가 있는 결과를 출력하기 위해 전체 블록을 0으로 설정하는 것이 정말 좋은 생각입니까?
아니. 전혀 아니야.
당신의 동료가 제안하는 해결책은 형편없어요.이유는 다음과 같습니다.
전체 블록을 0으로 설정해도 아무것도 달성되지 않습니다.누군가가 실수로 free()'ed 블록을 사용하고 있기 때문에 블록 값으로는 알 수 없습니다.그런 종류의 블록은
calloc()
돌아온다.따라서 새로 할당된 메모리인지 아닌지는 알 수 없습니다.calloc()
또는malloc()+memset()
또는 이전에 당신의 코드에 의해 프리()된 것을 지정합니다.free()로 편집되는 모든 메모리 블록을 0으로 만드는 것이 프로그램에는 추가 작업입니다.free(NULL);
명확하게 정의되어 있어 조작이 불가능하기 때문에if
에 적응하다.if(ptr) {free(ptr);}
아무것도 달성하지 못합니다.부터
free(NULL);
no-op 이며 포인터를 다음과 같이 설정합니다.NULL
실제로 버그를 숨길 수 있습니다.어떤 함수가 실제로 호출하고 있는 경우free()
이미 free()'ed 포인터에서는 알 수 없습니다.대부분의 사용자 함수는 처음에 NULL 체크를 하기 때문에 통과를 고려하지 않을 수 있습니다.
NULL
에러 상태:
void do_some_work(void *ptr) {
if (!ptr) {
return;
}
/*Do something with ptr here */
}
그래서 그 모든 추가 체크와 제로 아웃은 아무것도 개선하지 못한 채 "강력함"을 가식적으로 느끼게 한다.이는 성능 및 코드 블러팅에 따른 추가 비용 문제를 다른 문제로 대체했을 뿐입니다.
그래서 그냥 전화했어free(ptr);
래퍼 기능이 없는 것은 심플하고 견고합니다(대부분).malloc()
구현이 더블 프리로 즉시 중단됩니다.이것은 좋은 일입니다).
' '우연히' '우연히' '우연히' 것은 일이 free()
와 할당된 메모리를 입니다.free()
을 어려워한다면, 입니다.만약 누군가가 이것을 다루기 힘들다고 생각한다면, C는 그들에게 적합한 언어가 아닐 것이다.
동료가 제안하는 바에 따라 함수가 두 번 호출될 경우 코드가 "안전"하게 됩니다(sleeske comment 참조). "안전"이 모든 사람에게 동일한 것을 의미하지는 않을 수 있습니다.;-).
코드와 함께 크래시 될 가능성이 높습니다.
Foo* foo = malloc( sizeof(Foo) );
DestroyFoo(foo);
DestroyFoo(foo); // will call free on memory already freed
동료의 코드 버전에서는, 이것은 크래시 되지 않습니다.
Foo* foo = malloc( sizeof(Foo) );
DestroyFoo(&foo);
DestroyFoo(&foo); // will have no effect
을 합니다.tmpFoo = 0;
(내부))DestroyFoo
로 충분합니다로 충분합니다. memset(tmpFoo, 0, sizeof(Foo));
메모리 해제 후 Foo가 잘못 액세스할 수 있는 추가 속성을 가지고 있는 경우 크래시를 방지할 수 있습니다.
그래서 저는 그렇다고 말하고 싶습니다. 그렇게 하는 것이 좋은 방법일지도 모릅니다.다만, 이것은, 악습이 있는 개발자에 대한 일종의 시큐러티일 뿐입니다(재할당하지 않고 두 번 전화할 필요는 전혀 없기 때문입니다).결국, 당신이 만드는 것은DestroyFoo
"불량"이지만 속도가 느립니다(잘못된 사용을 방지하기 위해 더 많은 작업을 수행합니다).
두 번째 솔루션은 지나치게 설계된 것 같습니다.물론 상황에 따라서는 더 안전할 수도 있지만 오버헤드와 복잡성이 너무 큽니다.
안전하게 하려면 , 메모리를 비운 후에 포인터를 NULL로 설정합니다.이것은 항상 좋은 관행입니다.
Foo* foo = malloc( sizeof(Foo) );
DestroyFoo(foo);
foo = NULL;
게다가 free()를 호출하기 전에 포인터가 NULL인지 아닌지를 확인하는 이유를 알 수 없습니다.free()가 작업을 대신하므로 이 작업은 필요하지 않습니다.
메모리를 0(또는 다른 것)으로 설정하는 것은 free()가 메모리를 클리어하지 않기 때문에 경우에 따라서는 좋은 방법입니다.메모리 영역을 빈 영역으로 표시하여 재사용할 수 있도록 합니다.메모리를 클리어 해, 아무도 읽을 수 없게 하려면 , 수동으로 메모리를 클리닝 할 필요가 있습니다.그러나 이 작업은 상당히 부하가 높기 때문에 모든 메모리를 해방하기 위해 사용해서는 안 됩니다.대부분의 경우 클리어하지 않아도 충분하며 불필요한 작업을 위해 성능을 희생할 필요가 없습니다.
void destroyFoo(Foo** foo)
{
if (!(*foo)) return;
Foo *tmpFoo = *foo;
*foo = NULL;
memset(tmpFoo, 0, sizeof(Foo));
free(tmpFoo);
}
당신의 동료 코드가 나쁜 이유는
- 은
foo
NULL
- 추가 변수를 만드는 것은 의미가 없다
- 값을 0으로 설정하는 것은 의미가 없다
- 구조물에 해제해야 할 것이 포함되어 있으면 구조물을 직접 해제하는 것은 효과가 없습니다.
동료분께서 생각하시는 것은 이 사용 사례입니다.
Foo* a = NULL;
Foo* b = createFoo();
destroyFoo(NULL);
destroyFoo(&a);
destroyFoo(&b);
그럴 때는 이렇게 해야 돼요.여기서 시험해 보다
void destroyFoo(Foo** foo)
{
if (!foo || !(*foo)) return;
free(*foo);
*foo = NULL;
}
.Foo
struct Foo
{
// variables
int number;
char character;
// array of float
int arrSize;
float* arr;
// pointer to another instance
Foo* myTwin;
};
이제 파기 방법을 정의하기 위해 먼저 작성 방법을 정의하겠습니다.
Foo* createFoo (int arrSize, Foo* twin)
{
Foo* t = (Foo*) malloc(sizeof(Foo));
// initialize with default values
t->number = 1;
t->character = '1';
// initialize the array
t->arrSize = (arrSize>0?arrSize:10);
t->arr = (float*) malloc(sizeof(float) * t->arrSize);
// a Foo is a twin with only one other Foo
t->myTwin = twin;
if(twin) twin->myTwin = t;
return t;
}
이제 생성 함수와 반대되는 파괴 함수를 쓸 수 있습니다.
Foo* destroyFoo (Foo* foo)
{
if (foo)
{
// we allocated the array, so we have to free it
free(t->arr);
// to avoid broken pointer, we need to nullify the twin pointer
if(t->myTwin) t->myTwin->myTwin = NULL;
}
free(foo);
return NULL;
}
여기서 테스트해 보세요.
int main ()
{
Foo* a = createFoo (2, NULL);
Foo* b = createFoo (4, a);
a = destroyFoo(a);
b = destroyFoo(b);
printf("success");
return 0;
}
불행하게도, 이 생각은 효과가 없다.
더블 프리를 의도한 것이라면, 다음과 같은 경우는 커버하고 있지 않습니다.
다음 코드를 가정합니다.
Foo *ptr_1 = (FOO*) malloc(sizeof(Foo));
Foo *ptr_2 = ptr_1;
free (ptr_1);
free (ptr_2); /* This is a bug */
제안서는 대신 다음과 같이 작성하는 것입니다.
Foo *ptr_1 = (FOO*) malloc(sizeof(Foo));
Foo *ptr_2 = ptr_1;
DestroyFoo (&ptr_1);
DestroyFoo (&ptr_2); /* This is still a bug */
는 " " 에의 두 DestroyFoo()
계속 크래쉬를 합니다.왜냐하면ptr_2
NULL 로 되지 , 되어 있는 하고 있습니다.NULL 의 경우, NULL 의 경우, NULL 의 경우, 의 경우 NULL 의 경우, NULL 의 경우, NULL 의 경우, NULL 의 경우는 해방되어 있습니다.
언급URL : https://stackoverflow.com/questions/34651234/is-this-a-good-way-to-free-memory
'programing' 카테고리의 다른 글
VueJ를 사용하여 텍스트 영역의 일부 문자를 차단하려면 어떻게 해야 합니까? (0) | 2022.07.28 |
---|---|
컴포넌트 내부의 단일 지점에서 vuejs 오류를 캡처하는 방법 (0) | 2022.07.28 |
정규 표현을 사용한 Java 값 추출 (0) | 2022.07.28 |
Vue.js: 자 컴포넌트 상태에 따라 부모 컴포넌트 버튼 비활성화 (0) | 2022.07.26 |
문자열 배열을 ArrayList로 변환 (0) | 2022.07.26 |