쓰레기 회수 시리즈(1): GC가 없으면 세계는 어떻게 될 것인가
1. 정적 분배: 정적 변수와 전역 변수의 분배 형식2.자동 분배: 창고에서 국부 변수에 메모리를 분배하는 방법3.동적 분배: 메모리 공간을 무더기에 동적 분배하여 데이터를 저장하는 방식
무더기 대상의 생명 주기를 어떻게 관리하는가가 바로 우리가 탐구해야 할 화제다.대상을 향한 측면에서 볼 때 모든 대상의 생명주기는 스스로 관리해야 한다. 즉, 대상으로서 자신이 언제 만들어지고 언제 소각되는지 아는 것이다.그러나 사실은 그렇지 않다. 대상 간에 상호 인용 관계가 있기 때문에 대상은 자신이 언제 사망을 선고할 수 있는지 모른다. 만약에 대상이 너무 일찍 석방되면'현공 인용'문제를 초래할 수 있다.너무 늦게 풀리거나 풀지 않으면 메모리 유출 문제를 초래할 수 있다.
C/C++에서 메모리 관리 방안을 제공합니다.malloc/new로 메모리를 표시할 수 있습니다. 이 메모리가 더 이상 필요하지 않을 때free/delete를 사용하여 시스템에 되돌려줍니다. 다음 코드를 보십시오.
int
main()
{
string *ptr = new
string;
// do something
delete
ptr;
}
이 과정은 매우 자연스럽고 또렷하지 않습니까?사용하기 전에 new로 메모리를 분배하고, 사용이 끝난 후에 delete로 삭제합니다.안타깝게도 현실 세계의 코드는 모두 이렇게 간단하지 않다. 개발자들은 여러 가지 이유로 메모리를 방출하는 것을 잊어버리거나 메모리를 정확하게 방출하지 못해 메모리가 유출된다.다음은 일반적인 메모리 유출 예입니다.
void
service(int
n, char
** names)
{
for
(int
i=0; i< n; i++)
{
char
* buf = (char
*) malloc(strlen(names[i]));
strncpy(buf,names[i], strlen(names[i]));
}
}
분명히 이곳에서 메모리를 방출하는 작업은 개발자가 해야 하지만 개발자는free()를 호출하는 것을 잊어버렸다.
void
service()
{
Node* x = new
Node("mid-autumn"
);
Node* ptr = x;
delete
x;
cout << ptr->data << endl;
}
이 코드의 문제는 delete를 잘못 호출하여 x의 메모리를 미리 방출하여 마지막 ptr->data 오류를 초래한 데 있다.번거로운 일은 이뿐만이 아닙니다. 다음 코드를 계속 보십시오.
int
main()
{
string *ptr = new
string[100];
// do something
delete
ptr;
}
이 코드는 보기에 매우 아름답다. new를 사용하여 100개의string 대상에게 메모리를 분배하고 마지막에는 delete를 사용하여 삭제한다. 그러나 불행하게도 이 코드는 여전히 정확하지 않다. 여기에 100개의string 대상을 분배한다. 마지막에 99개의string이 반드시 삭제되지 않을 수도 있다. 왜냐하면 같은 형식의 new와 delete를 사용하지 않았기 때문이다. 정확한 것은 다음과 같다.
int
main()
{
string *ptr = new
string[100];
// do something
delete
[] ptr;
}
마지막 그거 눈치챘어?간단하게 말하면 new를 호출할 때 []를 사용했고 delete를 호출할 때도 []를 사용했다.그러나 이 규칙은 우리가 말한 것처럼 이렇게 간단하지 않다. typedef가 있으면 new를 호출할 때 []를 사용하지 않았을 수도 있지만 delete를 호출할 때 []를 사용해야 한다. 예를 들어 아래의 코드와 같다.
typedef
string address[4];
int
main()
{
string *ptr = new
address;
// do something
delete
[] ptr;
}
악몽은 여기서 끝나지 않았습니다. 만약에 두 가지 유형의 Array와 Named Array가 있다면 그 중에서 Named Array는 Array에 공유됩니다. 다음 코드와 같습니다.
template
<class
T>
class
Array
{
public
:
Array(int
lowBound, int
highBound);
~Array();
private
:
vector<T> data;
size_t size;
int
lBound, int
hBound;
};
template
<class
T>
class
NamedArray : public
Array<T>
{
public
:
NamedArray(int
lowBound, int
highBound, const
string& name);
private
:
string* aName;
};
개발자는 위의 두 가지 유형을 사용할 때 다음과 같은 코드를 씁니다.
int
main()
{
NamedArray<int
> *pna = new
NamedArray<int
>(10,20,"Users"
);
Array<int
> *pa;
pa = pna;
// do something
delete
pa;
}
문제의 소재를 알아차렸습니까?마지막 줄에서 delete를 호출하면 aname이 차지하는 메모리를 방출할 수 없습니다. 왜냐하면 Array 형식의 분석 함수 ~ Array () 가virtual로 성명되지 않았기 때문입니다.그래서 부류의 분석 함수는 다태적 특성을 나타내지 않았다.
위의 몇 가지 예를 통해 알 수 있듯이 여러분은 메모리를 현시적으로 관리하는 어려움을 느꼈습니다. 그래서 C++에 스마트 지침의 개념이 등장하여 개발자가 수동으로 메모리를 관리하는 데 오류가 발생할 가능성을 줄였습니다. 가장 흔히 볼 수 있는 것은 STL의 std::auto 입니다.ptr, 본질적으로 그것도 일반적인 지침이다. 단지 std::autoptr는 분석할 때 delete 조작부호를 호출해서 포함된 대상을 자동으로 방출합니다.
int
main()
{
auto_ptr<int
> ptr(new int
(42));
cout << *ptr << endl;
// delete
}
명성이 자자한 Boost C++ 라이브러리에는 많은 스마트 포인터가 포함되어 있는데 예를 들어 작용역 포인터 boost::scopedptr, 공유 포인터 boost::sharedptr 등의 코드는 다음과 같습니다.
#include
<boost/shared_ptr.hpp>
#include
<vector>
int
main()
{
std::vector<boost::shared_ptr<int
> > v;
v.push_back(boost::shared_ptr<int
>(new int
(1)));
v.push_back(boost::shared_ptr<int
>(new int
(2)));
}
대상의 생명주기 관리는 현식 관리 방안을 사용한 다음에 은식 관리도 있다. 즉, 쓰레기 수거(Garbage Collection, 약칭 GC)이다. 세계 제2의 원로 언어인 Lisp에 가장 먼저 등장했다. Jean E. Sammet은 Lisp 언어의 가장 긴 공헌 중 하나가 비언어적 특징이라고 말한 적이 있다.즉 시스템이 메모리를 자동으로 처리하는 방법을 나타내는 지극히 기술적인 쓰레기 수거(GC, Garbage Collection)를 말한다.현재 많은 플랫폼과 언어가 쓰레기 회수 메커니즘, 예를 들어 JVM, CLR, Python 등을 지원한다.다음 글에서는 몇 가지 고전적인 쓰레기 회수 알고리즘을 소개할 것이다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Vector & Matrix스칼라 : 하나의 숫자로만 이루어진 데이터 (크기만 있고 방향이 없는 물리량) 벡터 : 여러 숫자로 이루어진 데이터 레코드. 매트릭스 : 벡터가 여럿인 데이터집합 벡터의 크기는 스칼라배를 통해 표현할 수 있다. *내...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.