C++에서 힙과 스택의 차이점

C++에서 메모리는 힙, 스택, 자유 저장 영역, 전역/정적 저장 영역 및 상수 저장 영역의 다섯 영역으로 나뉩니다.

1. 스택

스택은 필요할 때 컴파일러에 의해 할당되고 필요하지 않을 때 자동으로 지워지는 변수의 저장 영역입니다. 내부 변수는 일반적으로 지역 변수, 함수 매개 변수 등입니다.

2. 힙

힙은 new에 의해 할당된 메모리 블록입니다.해당 릴리스 컴파일러는 신경쓰지 않고 애플리케이션에 의해 제어됩니다.일반적으로 new는 삭제에 해당합니다. 프로그래머가 해제하지 않으면 운영 체제는 프로그램 종료 후 자동으로 재활용합니다.

3. 무료 저장 공간

여유 저장 영역은 malloc() 등에 의해 할당된 메모리 블록입니다. 힙과 매우 유사하지만 수명을 종료하기 위해 자유를 사용합니다.

4. 전역/정적 저장 영역

전역/정적 저장 영역, 전역 변수와 정적 변수는 같은 메모리 블록에 할당되는데, 이전 C 언어에서는 전역 변수를 초기화와 미초기화로 나눕니다(전역 변수와 정적 변수를 한 영역에 초기화, 초기화되지 않은 전역 변수 정적 변수는 서로 인접한 다른 영역에 있으며 초기화되지 않은 개체 저장 영역은 void*를 통해 액세스 및 조작할 수 있으며 프로그램 종료 후 시스템에서 해제됨) C++에서는 이러한 구분이 없으며 공유합니다. 같은 메모리 영역.

5. 일정한 저장 공간

상수 저장 영역, 비교적 특수한 저장 영역으로 상수를 저장하고 수정할 수 없습니다.

힙과 스택의 명확한 구분

//main.cpp

inta=0; //글로벌 초기화 영역

char*p1; //초기화되지 않은 전역 영역

기본()

{

intb; // 스택

chars[] = "abc"; // 스택

char*p2; // 스택

char*p3="123456"; //123456은 상수 영역에 있고 p3은 스택에 있습니다.

staticintc=0; //전역(정적) 초기화 영역

p1= (문자*)malloc(10);

p2= (char*)malloc(20); //힙 영역에는 10바이트와 20바이트의 할당 영역이 있다.

strcpy(p1, "123456"); //123456은 상수 영역에 배치되며 컴파일러는 이를 최적화하고 p3이 가리키는 "123456"을 한 위치에 놓을 수 있습니다.

}

힙 영역과 스택 영역에 저장 호출된 함수가 활성화되면 해당 함수의 비정적 변수나 포인터가 저장됨 malloc에 ​​의해 할당된 메모리 공간은 힙 영역에 배치되지만 포인터는 반환됨 malloc 할당 후 스택 영역에 있습니다. .

힙 및 스택에 대한 이론적 지식

스택 스택: 시스템에서 자동으로 할당합니다. 예를 들어 함수에서 지역 변수 int b를 선언하면 시스템이 자동으로 스택에 b를 위한 공간을 생성합니다.

힙 힙: 프로그래머가 신청하고 크기를 지정해야 함 C에서는 p1 = (char *)malloc(10)과 같은 malloc 함수, C++에서는 p2 = (char *)malloc과 같은 new 연산자 사용 (10) 그러나 p1과 p2 자체가 스택에 있음을 유의하십시오.

보이드에프()

{

int*p=newint[5];

}

이 짧은 코드에는 힙과 스택이 포함되어 있습니다.new를 볼 때 먼저 힙 메모리를 할당했다고 생각해야 하므로 포인터 p는 어떻습니까? 그는 스택 메모리의 일부를 할당했으므로 이 문장의 의미는 다음과 같습니다. 힙 메모리의 일부를 가리키는 포인터 p가 스택 메모리에 저장됩니다. 프로그램은 먼저 힙에 할당된 메모리의 크기를 결정한 다음 operator new를 호출하여 메모리를 할당한 다음 메모리의 첫 번째 주소를 반환하고 스택에 넣습니다. VC6에서 분해 코드는 다음과 같습니다.

00401028 푸시 14h

0040102A콜 교환원new(00401060)

0040102F esp,4 추가

00401032 mov dwordptr [ebp-8],eax

00401035 mov eax,dword ptr [ebp-8]

00401038 mov dwordptr [ebp-4],eax

여기서는 단순성을 위해 메모리를 해제하지 않았으므로 어떻게 해제합니까? 삭제 p입니까? 오, 틀렸어. delete []p여야 합니다. 이것은 컴파일러에 알리는 것입니다. 내가 삭제하는 것은 배열이고 VC6는 해당 쿠키 정보에 따라 메모리를 해제합니다. 좋아, 주제로 돌아가자: 힙과 스택의 차이점은 무엇인가? 주요 차이점은 다음과 같습니다.

1. 다른 관리 방법;

관리 방법: 스택의 경우 수동 제어 없이 컴파일러에서 자동으로 관리하고, 힙의 경우 릴리스 작업을 프로그래머가 제어하므로 메모리 누수가 발생하기 쉽습니다.

2. 공간의 크기가 다릅니다.

공간 크기: 일반적으로 32비트 시스템에서 힙 메모리는 4G에 도달할 수 있습니다. 이러한 관점에서 힙 메모리에는 거의 제한이 없습니다. 하지만 스택의 경우 일반적으로 일정한 공간 크기가 있습니다.예를 들어 VC6에서 기본 스택 공간 크기는 1M입니다. 물론 다음과 같이 수정할 수 있습니다. 프로젝트를 열고 다음과 같이 메뉴를 조작합니다. 프로젝트->설정->링크, 범주에서 출력을 선택한 다음 예약에서 스택 및 커밋의 최대값을 설정합니다. 참고: 예약의 최소값은 4바이트이며 커밋은 가상 메모리의 페이지 파일에 예약됩니다. 더 크게 설정하면 스택이 더 큰 값을 열어 메모리 오버헤드와 시작 시간이 증가할 수 있습니다.

3. 조각을 생성할 수 있는지 여부가 다릅니다.

힙의 경우 잦은 신규/삭제는 필연적으로 메모리 공간의 불연속성을 야기하여 많은 수의 조각이 발생하고 프로그램 효율성이 저하됩니다. 스택의 경우 이 문제는 존재하지 않습니다. 왜냐하면 스택은 선입선출 대기열이고 일대일 대응이기 때문에 메모리 블록이 중간에서 튀어나오는 것이 결코 불가능하기 때문입니다. stack.위의 역방향 스택의 내용이 팝업되었습니다.자세한 내용은 데이터 구조를 참조하고 여기에서 하나씩 설명하지 않습니다.

4. 다른 성장 방향;

성장 방향: 힙의 성장 방향은 메모리 주소가 증가하는 위쪽 방향이고, 스택의 경우 증가 방향은 메모리 주소가 감소하는 아래쪽 방향입니다.

5. 다른 배포 방법;

힙은 동적으로 할당되며 정적으로 할당된 힙은 없습니다. 스택을 할당하는 방법에는 정적 할당과 동적 할당의 두 가지가 있습니다. 정적 할당은 지역 변수 할당과 마찬가지로 컴파일러에서 수행합니다. 동적 할당은 alloca 함수에 의해 할당되지만 스택의 동적 할당은 힙과 다릅니다.그의 동적 할당은 우리의 수동 구현 없이 컴파일러에 의해 해제됩니다.

6. 유통 효율이 다릅니다.

스택은 기계 시스템에서 제공하는 데이터 구조입니다.컴퓨터는 맨 아래 계층에서 스택을 지원합니다: 스택의 주소를 저장하기 위한 특수 레지스터를 할당하고 스택을 푸시하고 팝하는 특수 명령이 있습니다. 스택의 효율성이 상대적으로 높다고 판단합니다. 힙은 C/C++ 함수 라이브러리에 의해 제공되며 그 메커니즘은 매우 복잡합니다.예를 들어 메모리 블록을 할당하기 위해 라이브러리 함수는 힙 메모리에서 사용 가능한 공간이 충분하지 않은 경우 너무 많은 메모리 조각화) 시스템 기능을 호출하여 프로그램 데이터 세그먼트의 메모리 공간을 늘릴 수 있으므로 충분한 메모리를 할당한 다음 반환을 수행할 수 있습니다. 분명히 힙은 스택보다 훨씬 덜 효율적입니다.

요약하면 스택에 비해 많은 수의 신규/삭제를 사용하기 때문에 많은 양의 메모리 단편화를 일으키기 쉽고 특별한 시스템 지원이 없기 때문에 효율성이 매우 낮습니다. 사용자 모드와 코어 모드 간 전환 가능성, 메모리 응용 프로그램이 더 비쌉니다. 따라서 프로그램에서 스택이 가장 많이 사용되며, 함수 호출도 스택을 이용하여 완료되며, 함수 호출 과정에서 매개변수, 반환 주소, EBP, 지역 변수 등이 스택에 저장된다. 따라서 가급적 힙보다는 스택을 사용하는 것을 권장합니다. 스택은 많은 이점이 있지만 힙에 비해 유연성이 높지 않기 때문에 많은 양의 메모리 공간을 할당하기 위해 힙을 사용하는 것이 더 나을 때도 있습니다.

힙이건 스택이건 아웃 오브 바운드 현상의 발생을 방지할 필요가 있다. 프로그램의 힙 및 스택 구조가 파괴되어 예기치 않은 결과가 발생합니다.프로그램 실행 중에 위의 문제가 발생하지 않으면 여전히 조심해야 하며 언제든지 충돌할 수 있으며 그 당시에는 디버깅하기가 꽤 어려웠습니다 :) 누군가 스택을 함께 넣으면 힙이 아니라 스택을 의미합니다 . 하하!

static은 변수의 저장 및 가시성을 제어하는 ​​데 사용됩니다.

함수 내부에 정의된 변수는 프로그램이 정의에 따라 실행될 때 컴파일러가 스택에 공간을 할당하고 스택의 함수가 할당한 공간은 함수 실행이 끝날 때 해제되므로 문제가 발생합니다. : 이 변수의 값을 다음 호출 때까지 함수에 저장하고 싶다면 어떻게 해야 할까요? 가장 쉽게 생각할 수 있는 것은 전역 변수를 정의하는 것이지만, 전역 변수로 정의하는 것은 많은 단점이 있는데, 가장 분명한 단점은 이 변수의 접근 범위를 소멸시킨다는 것입니다(그래서 이 함수에 정의된 변수는 이 기능에 의해서만 제어됨). 데이터 객체는 특정 객체가 아닌 클래스 전체를 서비스해야 함과 동시에 클래스의 캡슐화를 파괴하지 않도록 노력해야 합니다. 즉, 이 멤버는 클래스 내부에 숨겨져 외부에 보이지 않아야 합니다. . 정적을 사용하여 목표를 달성할 수 있습니다.

정전기의 내부 메커니즘

프로그램 실행을 시작할 때 정적 데이터 멤버가 있어야 합니다. 프로그램이 실행되는 동안 함수가 호출되기 때문에 정적 데이터 멤버는 함수 내에서 할당 및 초기화될 수 없습니다. 이러한 방식으로 공간 할당에는 세 가지 가능한 위치가 있습니다. 하나는 클래스 선언이 있는 클래스 외부 인터페이스의 헤더 파일이고 두 번째는 클래스 멤버 함수 정의가 있는 클래스 정의의 내부 구현입니다. ; 세 번째는 응용 프로그램의 주요 기능() 전역 데이터 선언 및 함수 이전 정의입니다. 정적 데이터 멤버는 실제로 공간을 할당해야 하므로 클래스 선언에서 정의할 수 없습니다(데이터 멤버만 선언할 수 있음). 클래스 선언은 클래스의 "크기 및 사양"만 선언하고 실제 메모리 할당을 수행하지 않으므로 클래스 선언에 정의를 작성하는 것은 잘못된 것입니다. 또한 클래스를 사용하는 여러 소스 파일에서 반복적으로 정의되기 때문에 헤더 파일의 클래스 선언 외부에서 정의할 수 없습니다. 스택의 공간이 아닌 프로그램의 정적 저장 영역에 변수를 저장하도록 컴파일러에 지시하기 위해 static이 도입되었습니다. 정적 데이터 멤버는 정의된 순서대로 초기화됩니다. 정적 멤버가 중첩될 때, 중첩 멤버가 초기화되었는지 확인해야 합니다. 제거 순서는 초기화의 역순입니다.

정적의 장점

모든 객체에 공통이므로 메모리를 절약할 수 있으므로 여러 객체의 경우 정적 데이터 멤버는 한 곳에만 저장되고 모든 객체에서 공유됩니다. 정적 데이터 멤버의 값은 각 개체에 대해 동일하지만 값을 업데이트할 수 있습니다. 정적 데이터 멤버의 값이 한 번 업데이트되는 한 모든 개체는 동일한 업데이트된 값에 액세스할 수 있으므로 시간 효율성을 높일 수 있습니다. 정적 데이터 멤버를 참조할 때 다음 형식을 사용하십시오. <클래스 이름>::<정적 멤버 이름> 정적 데이터 멤버(즉, 공용 멤버)의 액세스 권한이 허용하는 경우 프로그램에서 정적 데이터 멤버를 참조할 수 있습니다. 위의 형식에 따라 .

(1) 클래스의 정적 멤버 함수는 클래스가 아닌 전체 클래스에 속하는 객체이므로 this 포인터가 없으므로 클래스의 정적 데이터 및 정적 멤버 함수에만 액세스할 수 있습니다. (2) 정적 멤버 함수는 가상 함수로 정의할 수 없습니다. (3) 정적 멤버는 클래스 내에서 선언되어 외부에서 동작하기 때문에 그 주소를 취하는 동작이 다소 특수하다. . (4) 정적 멤버 함수에는 this 포인터가 없기 때문에 비멤버 함수와 거의 동일하며 결과적으로 예상치 못한 이점이 있습니다. 콜백 함수가 되어 C++ 및 c 기반 x 윈도우 시스템을 결합할 수 있습니다. 동시에 스레드 기능에 성공적으로 적용되었습니다. (5) 정적은 프로그램의 시간 및 공간 오버헤드를 증가시키지 않으며, 반대로 상위 클래스의 정적 멤버에 대한 하위 클래스의 액세스 시간을 단축하여 하위 클래스의 메모리 공간을 절약합니다. (6) 정적 데이터 멤버의 경우 <definition or description> 앞에 static 키워드를 추가합니다. (7) 정적 데이터 멤버는 정적으로 저장되므로 초기화해야 합니다. (8) 정적 멤버 초기화는 일반적인 데이터 멤버 초기화와 달리 초기화는 클래스 외부에서 이루어지며 일반 정적 변수나 객체와의 혼동을 피하기 위해 앞에 static을 추가하지 않으며 이를 위한 접근 제어 기호는 private, public 등이다. 멤버는 초기화 중에 추가되지 않습니다. 범위 연산자는 초기화 중에 속한 클래스를 나타내는 데 사용되므로 정적 데이터 멤버 초기화 형식을 얻습니다. <데이터 유형><클래스 이름>::<정적 데이터 멤버 이름>= <값> (9) 방지하기 위해 부모 클래스의 영향에 대해 부모 클래스의 영향을 보호하기 위해 부모 클래스와 동일한 하위 클래스에 정적 변수를 정의할 수 있습니다. 여기서 한 가지 주의할 점은 부모 클래스와 하위 클래스가 정적 멤버를 공유한다고 하는데, 정적 멤버를 반복적으로 정의했는데 이것이 오류가 될까요? 아니요, 우리 컴파일러는 고유한 플래그를 생성하기 위해 이름을 맹글링하는 깔끔한 트릭을 사용합니다.

전역 변수 정적 변수

static으로 선언된 변수는 C 언어에서 두 가지 특성을 갖습니다.

  1. 변수는 프로그램의 전역 저장 영역에 배치되므로 다음 호출 시 원래 할당을 유지할 수 있습니다. 이것은 그것과 스택 변수 및 힙 변수의 차이점입니다.

  1. 변수는 정적을 사용하여 변수 범위 내에서만 볼 수 있음을 컴파일러에 알립니다. 이것이 전역 변수와 차이점입니다. 팁: A. 전역 변수가 단일 C 파일에서만 액세스되는 경우 이 변수를 정적 전역 변수로 변경하여 모듈 간의 결합을 줄일 수 있습니다. B. 전역 변수가 단일 함수에서만 액세스되는 경우 다음을 수행할 수 있습니다. 이 변수를 함수의 정적 로컬 변수로 변경하여 모듈 간의 결합을 줄임 C. 동적 전역 변수, 정적 전역 변수 및 정적 로컬 변수에 액세스하는 함수를 설계하고 사용할 때 재진입 문제를 고려해야 합니다. D. 재진입 함수가 필요한 경우 함수에서 정적 변수를 사용하지 않아야 합니다(이러한 함수는 "내부 메모리" 함수가 있는 함수라고 함). E. 정적 변수는 함수에서 사용해야 합니다. 반환 값은 포인터 타입으로 반환 값은 정적 지역 변수의 주소여야 하며 자동 타입이면 오류 포인터를 반환합니다. 함수 앞에 static을 추가하면 함수가 정적 함수가 됩니다. 그러나 여기서 "정적"의 의미는 저장 방법을 말하는 것이 아니라 이 파일로 제한되는 기능의 범위를 나타냅니다(따라서 내부 함수라고도 함). 내부 함수를 사용하는 이점은 다른 사람들이 다른 함수를 작성할 때 그들이 정의한 함수가 다른 파일의 함수와 같은 이름을 가질지 여부에 대해 걱정할 필요가 없다는 것입니다. 확장된 분석: static이라는 용어는 특이한 역사를 가지고 있습니다.원래 키워드 static은 블록을 종료한 후에도 지속되는 지역 변수를 나타내기 위해 C에서 도입되었습니다. 결과적으로 static은 C에서 두 번째 의미를 갖습니다. 다른 파일에서 액세스할 수 없는 전역 변수 및 함수를 나타내는 데 사용됩니다. 새 키워드 도입을 피하기 위해 정적 키워드는 여전히 이 두 번째 의미를 나타내는 데 사용됩니다. 마지막으로 C++는 이 키워드를 재사용하고 이전과 다른 세 번째 의미를 부여했습니다. 해당 클래스에 속하는 특정 객체가 아니라 해당 클래스에 속하는 변수 및 함수를 나타냅니다(Java에서 이 키워드와 동일한 의미).

전역 변수, 정적 전역 변수, 정적 지역 변수 및 지역 변수의 차이점

변수는 전역 변수, 정적 전역 변수, 정적 지역 변수 및 지역 변수로 나눌 수 있습니다. 저장 영역에 따라 메모리의 정적 저장 영역에는 전역 변수, 정적 전역 변수 및 정적 로컬 변수가 모두 저장되고 메모리의 스택 영역에는 로컬 변수가 저장됩니다. 범위 측면에서 전역 변수는 전체 프로젝트 파일에서 유효하고, 정적 전역 변수는 자신이 정의된 파일에서만 유효하며, 정적 지역 변수는 정의된 함수에서만 유효하지만 프로그램은 할당만 합니다. 한 번 메모리에 저장되고 함수가 반환된 후에는 변수가 사라지지 않고 로컬 변수는 정의된 함수 내에서 유효하지만 함수가 반환된 후에는 무효가 됩니다. 전역 변수(외부 변수)의 설명 앞에 static을 붙여 정적 전역 변수를 구성합니다. 전역 변수 자체는 정적 저장 방법이며 정적 전역 변수는 물론 정적 저장 방법입니다. 저장 방식에는 둘 사이에 차이가 없습니다. 둘의 차이점은 비정적 전역 변수의 범위가 소스 프로그램 전체라는 점인데, 소스 프로그램이 여러 소스 파일로 구성된 경우 비정적 전역 변수는 각 소스 파일에서 유효합니다. 정적 전역 변수는 범위를 제한합니다. 즉, 변수가 정의된 소스 파일에서만 유효하며 동일한 소스 프로그램의 다른 소스 파일에서는 사용할 수 없습니다. 정적 전역 변수의 범위는 하나의 소스 파일로 제한되기 때문에 이 소스 파일의 함수에서만 공유할 수 있으므로 다른 소스 파일에서 오류가 발생하는 것을 방지할 수 있습니다. 위의 분석을 통해 지역 변수를 정적 변수로 변경하면 저장 방식, 즉 수명이 변경됨을 알 수 있습니다. 전역 변수를 정적 변수로 변경하면 범위가 변경되고 사용 범위가 제한됩니다. 정적 함수는 일반 함수와 범위가 다릅니다. 이 문서에서만. 현재 소스 파일에서만 사용되는 함수는 내부 함수(정적)로 기술하고, 내부 함수는 현재 소스 파일에서 기술 및 정의해야 합니다. 현재 소스 파일 외부에서 사용할 수 있는 함수의 경우 이러한 함수를 사용하는 소스 파일에 이 헤더 파일이 포함되어야 함을 헤더 파일에 명시해야 합니다. 정적 전역 변수와 일반 전역 변수의 차이점은 무엇입니까? 정적 전역 변수는 한 번만 초기화됨, 다른 파일 단위에서 참조되는 것을 방지하기 위해 정적 지역 변수와 일반 지역 변수의 차이점은 무엇입니까: 정적 지역 변수는 한 번만 초기화되며 다음은 마지막 결과 값을 기준으로 초기화됩니다. 차이점은 무엇입니까 정적 함수와 일반 함수 사이: 정적 함수는 메모리에 하나의 복사본만 있고 일반 함수는 호출할 때마다 복사본을 유지합니다.

전역 변수와 정적 변수는 수동으로 초기화하지 않으면 컴파일러에서 0으로 초기화됩니다. 지역 변수의 값을 알 수 없습니다.

Guess you like

Origin blog.csdn.net/allexw/article/details/129067728