섹션 2 T클래스 원자
System.pas 유닛에서 TClass는 다음과 같이 정의됩니다.
TClass = TObject의 클래스;
이는 TClass가 TObject의 클래스임을 의미합니다. TObject 자체가 클래스이기 때문에 TClass는 소위 클래스의 클래스입니다.
개념적으로 TClass는 클래스의 한 종류, 즉 클래스입니다. 그러나 우리는 DELPHI 클래스가 VMT 데이터 조각을 나타낸다는 것을 알고 있습니다. 따라서 클래스는 VMT 데이터 항목에 대해 정의된 유형이라고 볼 수 있습니다. 실제로는 VMT 데이터를 가리키는 포인터 유형입니다!
이전의 전통적인 C++ 언어에서는 클래스의 유형을 정의할 수 없었습니다. 객체가 컴파일되면 고정되고 클래스의 구조 정보가 절대 기계어 코드로 변환되므로 전체 클래스 정보가 메모리에 존재하지 않습니다. 일부 상위 객체 지향 언어는 동적 액세스와 클래스 정보 호출을 지원할 수 있지만 복잡한 내부 해석 메커니즘과 더 많은 시스템 리소스가 필요한 경우가 많습니다. DELPHI의 오브젝트 파스칼 언어는 고급 객체 지향 언어의 뛰어난 기능 중 일부를 흡수하는 동시에 프로그램을 기계어 코드로 직접 컴파일하는 전통적인 장점을 유지하여 고급 기능 및 프로그램 효율성 문제를 완벽하게 해결합니다.
DELPHI가 애플리케이션에서 완전한 클래스 정보를 유지하기 때문에 클래스의 VMT 데이터가 핵심 핵심 역할을 하는 런타임 시 클래스를 변환하고 식별하는 등의 고급 객체 지향 기능을 제공할 수 있습니다. 관심 있는 친구들은 System 유닛에서 AsClass와 IsClass의 두 가지 어셈블리 프로세스를 읽을 수 있습니다. 이는 클래스와 VMT 데이터에 대한 이해를 심화하기 위한 as 및 is 연산자의 구현 코드입니다.
클래스 유형을 사용하면 클래스를 변수로 사용할 수 있습니다. 클래스 변수는 특별한 개체로 이해될 수 있으며, 개체와 마찬가지로 클래스 변수의 메서드에 액세스할 수 있습니다. 예: 다음 프로그램 부분을 살펴보겠습니다.
유형
TSampleClass = TSampleObject의 클래스;
TSampleObject = 클래스( TObject )
공공의
생성자 생성;
소멸자 재정의;
클래스 함수 GetSampleObjectCount:Integer;
PROcedure GetObjectIndex:Integer;
끝;
var
aSampleClass : TSampleClass;
a클래스 : T클래스;
이 코드에서는 TSampleObject 클래스와 관련 클래스 유형 TSampleClass, 두 개의 클래스 변수 aSampleClass 및 aClass를 정의합니다. 또한 TSampleObject 클래스에 대한 생성자, 소멸자, 클래스 메서드 GetSampleObjectCount 및 개체 메서드 GetObjectIndex도 정의했습니다.
먼저 클래스 변수 aSampleClass와 aClass의 의미를 이해해보자.
분명히 정수 변수 i에 123개의 상수 값을 할당하는 것처럼 TSampleObject와 TObject를 상수 값으로 처리하여 aClass 변수에 할당할 수 있습니다. 따라서 클래스 유형, 클래스 및 클래스 변수 간의 관계는 유형, 상수 및 변수 간의 관계이지만 객체 수준이 아닌 클래스 수준입니다. 물론 TObject를 aSampleClass에 직접 할당하는 것은 합법적이지 않습니다. 왜냐하면 aSampleClass는 TObject 파생 클래스 TSampleObject의 클래스 변수이고 TObject에는 TSampleClass 유형과 호환되는 모든 정의가 포함되어 있지 않기 때문입니다. 반대로 TSampleObject는 TObject의 파생 클래스이고 TClass 유형과 호환되므로 TSampleObject를 Class 변수에 할당하는 것이 합법적입니다. 이는 객체 변수의 할당 및 유형 일치 관계와 정확히 유사합니다.
그럼, 클래스 메소드가 무엇인지 살펴보겠습니다.
소위 클래스 메소드란 위에서 정의한 GetSampleObjectCount 메소드와 같이 클래스 수준에서 호출되는 메소드를 말하는데, 이는 class 예약어로 선언된 메소드이다. 클래스 메소드는 객체 수준에서 호출되는 객체 메소드와 다릅니다. 객체 메소드는 이미 우리에게 익숙하며, 클래스 메소드는 항상 모든 클래스 객체의 공통 특성에 접근하고 제어하며 객체를 중앙에서 관리하는 수준에서 사용됩니다. TObject의 정의에서 ClassName, ClassInfo, NewInstance 등과 같은 수많은 클래스 메소드를 찾을 수 있습니다. 그 중 NewInstance도 virtual, 즉 가상 클래스 메소드로 정의되어 있다. 이는 파생 하위 클래스에서 NewInstance의 구현 메서드를 다시 작성하여 특별한 방법으로 해당 클래스의 개체 인스턴스를 생성할 수 있음을 의미합니다.
클래스 메소드에서 self 식별자를 사용할 수도 있지만 그 의미는 객체 메소드의 self와 다릅니다. 클래스 메소드의 self는 자신의 클래스, 즉 VMT에 대한 포인터를 나타내고, 객체 메소드의 self는 객체 자체, 즉 객체 데이터 공간에 대한 포인터를 나타냅니다. 클래스 메서드는 클래스 수준에서만 사용할 수 있지만 여전히 개체를 통해 클래스 메서드를 호출할 수 있습니다. 예를 들어, 객체 TObject의 클래스 메소드 ClassName은 aObject.ClassName 문을 통해 호출될 수 있습니다. 왜냐하면 객체 포인터가 가리키는 객체 데이터 공간의 처음 4바이트는 클래스 VMT에 대한 포인터이기 때문입니다. 반대로 클래스 수준에서는 객체 메서드를 호출할 수 없으며 TObject.Free와 같은 문은 불법이어야 합니다.
생성자는 클래스 메소드이고 소멸자는 객체 메소드라는 점은 주목할 가치가 있습니다!
무엇? 생성자는 클래스 메소드이고 소멸자는 객체 메소드입니다! 실수가 있었나요?
객체를 생성할 때 다음과 유사한 명령문을 명확하게 사용합니다.
aObject := TObject.Create;
분명히 TObject 클래스의 Create 메소드를 호출하고 있습니다. 객체를 삭제할 때 다음 문을 사용하십시오.
aObject.Destroy;
Free 메소드를 사용하여 객체를 해제하더라도 해당 객체의 Destroy 메소드가 간접적으로 호출됩니다.
그 이유는 매우 간단합니다. 객체가 생성되기 전에는 객체가 아직 존재하지 않고 클래스 메소드만 사용하여 객체를 생성할 수 있습니다. 반대로 객체를 삭제하면 클래스가 아닌 기존 객체가 삭제됩니다.
마지막으로 가상 생성자 문제에 대해 논의해 보겠습니다.
기존 C++ 언어에서는 가상 소멸자를 구현할 수 있지만 가상 생성자를 구현하는 것은 어려운 문제입니다. 왜냐하면 전통적인 C++ 언어에는 클래스 유형이 없기 때문입니다. 전역 객체의 인스턴스는 컴파일 시 전역 데이터 공간에 존재하며, 함수의 로컬 객체도 컴파일 시 스택 공간에 매핑되는 인스턴스입니다. 동적으로 생성된 객체라도 new 연산자를 사용하여 고정된 클래스 구조에 배치됩니다. 힙 공간이고 생성자는 생성된 객체 인스턴스를 초기화하는 객체 메서드일 뿐입니다. 기존 C++ 언어에는 실제 클래스 메소드가 없습니다. 소위 정적 클래스 기반 메소드가 정의될 수 있지만 가상 클래스 메소드는 말할 것도 없이 특정 객체만 대상으로 할 수 있습니다. 효율적입니다. 따라서 전통적인 C++ 언어에서는 특정 개체 인스턴스가 생성되기 전에는 생성할 개체를 기반으로 개체 자체를 구성하는 것이 불가능하다고 믿습니다. 그것은 실제로 불가능합니다. 왜냐하면 이것은 논리에서 자기모순적인 역설을 만들 것이기 때문입니다!
그러나 동적 클래스 유형 정보, 진정한 가상 클래스 메소드, DELPHI의 클래스를 기반으로 구현된 생성자의 핵심 개념 덕분에 가상 생성자가 구현될 수 있습니다. 사물은 수업을 통해 생산되며, 사물은 성장하는 아기와 같고, 수업은 엄마이다. 아기 자신은 미래에 어떤 사람이 될지 모르지만, 엄마들은 자신만의 교육 방법을 활용하여 다양한 자녀를 양육한다. . 여러분, 원칙은 같습니다.
다양한 유형의 컨트롤이 자체 생성 메서드를 구현할 수 있도록 생성자 Create가 가상으로 정의되는 것은 TComponent 클래스의 정의에 있습니다. 이것이 TClass가 만든 클래스 같은 개념의 위대함이자 DELPHI의 위대함입니다.
................................................. ..
3장 WIN32의 시간과 공간관
나의 늙은 아버지는 어린 손자가 땅바닥에서 장난감을 가지고 노는 것을 보더니 나에게 말했다. "이 아이는 당신의 어렸을 때와 똑같습니다. 그는 물건 분해하기를 좋아하고 끝까지 본 후에야 멈춥니다." 어렸을 때를 생각해보면 장난감 자동차, 작은 알람시계, 오르골 등을 자주 분해해서 어머니에게 혼나는 일이 많았습니다.
내가 처음으로 컴퓨터의 기본 원리를 이해한 것은 내가 분해한 오르골과 관련이 있었습니다. 고등학교 시절 만화책에서 흰 수염을 기른 할아버지가 스마트 기계의 이론을 설명하고 있었고, 콧수염을 기른 삼촌이 컴퓨터와 오르골에 대해 이야기하고 있었습니다. 그들은 컴퓨터의 중앙 처리 장치가 오르골의 발음에 사용되는 악보의 줄이고, 컴퓨터 프로그램은 오르골의 작은 원통에 빽빽하게 들어찬 돌기라고 말했습니다. 중앙 처리 장치의 회전에 따라 명령 포인터가 자연스럽게 움직이며 작은 원통의 음악을 나타내는 범프가 음악 리드의 진동을 제어하여 중앙 프로세서의 프로그램 실행과 동일한 명령을 생성합니다. 오르골은 장인이 작은 원통에 새긴 악보에 따라 아름다운 선율을 연주합니다. 컴퓨터는 프로그래머가 미리 프로그래밍한 프로그램을 기반으로 복잡한 처리를 완료합니다. 대학에 진학한 후, 흰 수염을 기른 노인은 과학의 거인 튜링이었고, 그의 유한 오토마타 이론은 전체 정보 혁명의 발전을 이뤘고, 콧수염을 기른 삼촌은 컴퓨터의 아버지인 폰 노이만이라는 것을 알게 되었습니다. 컴퓨터 아키텍처는 여전히 컴퓨터의 주요 아키텍처 구조입니다. 오르골이 헛되이 분해되지 않았기 때문에 어머니는 안심하실 수 있습니다.
단순하고 심오한 이해가 있어야만 심오하고 간결한 창작물을 만들 수 있습니다.
이 장에서는 Windows 32비트 운영 체제에서의 프로그래밍과 관련된 기본 개념을 논의하고 WIN32에서 시간과 공간에 대한 올바른 보기를 설정합니다. 이 장을 읽은 후 프로그램, 프로세스 및 스레드에 대해 더 깊이 이해하고 실행 파일, 동적 링크 라이브러리 및 런타임 패키지의 원리를 이해하고 글로벌 데이터, 로컬 데이터 및 메모리의 매개 변수에 대한 진실을 명확하게 볼 수 있기를 바랍니다. .
섹션 1 프로세스 이해
역사적인 이유로 인해 Windows는 DOS에서 시작되었습니다. DOS 시대에는 항상 프로그램이라는 개념만 있었고 프로세스라는 개념은 없었습니다. 당시에는 UNIX, VMS 등 일반 운영체제에만 프로세스라는 개념이 있었고, 다중 프로세스란 미니컴퓨터, 터미널, 다중 사용자 등을 의미하며, 이는 곧 돈을 의미하기도 했습니다. 대부분의 경우 상대적으로 저렴한 마이크로컴퓨터와 DOS 시스템만 사용할 수 있었는데, 운영체제를 공부하면서부터 프로세스와 미니컴퓨터를 접하기 시작했습니다.
Windows 3 이후였습니다. 예전에는 DOS에서는 동시에 하나의 프로그램만 실행할 수 있었지만 Windows에서는 여러 프로그램을 동시에 실행할 수 있었습니다. DOS에서는 프로그램을 실행하는 동안 동일한 프로그램을 동시에 실행할 수 없지만 Windows에서는 동일한 프로그램의 복사본을 두 개 이상 동시에 실행할 수 있으며 실행 중인 프로그램의 각 복사본은 프로세스입니다. 더 정확하게 말하면 모든 프로그램이 실행될 때마다 작업이 생성되고 각 작업은 프로세스입니다.
프로그램과 프로세스를 함께 이해하면 프로그램이라는 단어는 정적인 것을 가리키는 것으로 간주될 수 있습니다. 일반적인 프로그램은 EXE 파일 또는 EXE 파일과 여러 DLL 파일로 구성된 정적 코드 및 데이터입니다. 프로세스는 메모리에서 동적으로 실행되는 코드와 동적으로 변경되는 데이터인 프로그램의 실행입니다. 정적 프로그램을 실행해야 하는 경우 운영 체제는 이 작업을 위해 특정 메모리 공간을 제공하고 정적 프로그램 코드와 데이터를 이러한 메모리 공간으로 전송하며 이 공간에 프로그램 코드와 데이터를 재배치하고 매핑합니다. 내부에서 실행되어 동적 프로세스를 생성합니다.
동시에 실행되는 동일한 프로그램의 두 복사본은 시스템 메모리에 두 개의 프로세스 공간이 있지만 해당 프로그램 기능은 동일하지만 동적으로 변경되는 상태가 다르다는 것을 의미합니다.
프로세스의 실행 시간 측면에서 각 프로세스가 동시에 실행되는 것을 전문 용어로 병렬 실행 또는 동시 실행이라고 합니다. 그러나 이것은 주로 운영 체제가 우리에게 주는 피상적인 느낌입니다. 실제로 각 프로세스는 시간 공유 방식으로 실행됩니다. 즉, 각 프로세스는 프로세스의 프로그램 명령을 실행하기 위해 차례로 CPU 시간을 차지합니다. CPU의 경우 한 프로세스의 명령만 동시에 실행됩니다. 운영체제는 CPU에서 실행되는 각 프로세스의 현재 상태를 지속적으로 저장하고 전환하여 각 예약된 프로세스가 완전하고 지속적으로 실행되고 있다고 생각하도록 합니다. 프로세스의 시분할 스케줄링은 매우 빠르기 때문에 프로세스가 모두 동시에 실행되고 있다는 인상을 줍니다. 실제로 진정한 동시 작업은 다중 CPU 하드웨어 환경에서만 가능합니다. 나중에 스레드에 대해 이야기할 때 스레드가 프로세스를 실제로 구동하는 것이며 더 중요하게는 프로세스 공간을 제공한다는 사실을 알게 될 것입니다.
프로세스가 차지하는 공간 측면에서 각 프로세스 공간은 상대적으로 독립적이며 각 프로세스는 자체 독립 공간에서 실행됩니다. 프로그램에는 코드 공간과 데이터 공간이 모두 포함됩니다. 코드와 데이터는 모두 프로세스 공간을 차지합니다. Windows는 각 프로세스에 필요한 데이터 공간에 실제 메모리를 할당하고 일반적으로 코드 공간에 대한 공유 방법을 사용하여 프로그램의 하나의 코드를 프로그램의 여러 프로세스에 매핑합니다. 즉, 프로그램에 100K의 코드가 있고 100K의 데이터 공간이 필요한 경우, 즉 총 200K의 프로세스 공간이 필요하면 운영 체제는 프로그램이 처음 실행될 때 200K의 프로세스 공간을 할당하고 200K의 프로세스 공간을 할당합니다. 프로그램이 두 번째 실행될 때 운영 체제는 100K의 데이터 공간만 할당하는 반면 코드 공간은 이전 프로세스의 공간을 공유합니다.
위 내용은 Windows 운영체제에서의 프로세스에 대한 기본적인 시공간 관점입니다. 실제로 Windows의 16비트 운영체제와 32비트 운영체제에서는 프로세스에 대한 시공간 관점에 큰 차이가 있습니다.
시간적으로 보면 Windows 3.x와 같은 16비트 Windows 운영 체제의 프로세스 관리는 실제로는 단순한 다중 작업 관리 운영 체제에 불과합니다. 게다가 운영 체제의 작업 스케줄링은 수동적입니다. 작업이 메시지 처리를 포기하지 않으면 운영 체제는 기다려야 합니다. 16비트 Windows 시스템의 프로세스 관리 결함으로 인해 프로세스가 실행될 때 CPU 리소스를 완전히 차지합니다. 당시 마이크로소프트는 16비트 윈도우가 다른 작업을 계획할 수 있는 기회를 주기 위해 윈도우 애플리케이션 개발자들이 마음이 넓은 프로그래머라고 칭찬했다. 운영 체제. 반대로 Windows 95 및 NT와 같은 WIN32 운영 체제에는 실제 다중 프로세스 및 멀티 태스킹 운영 체제 기능이 있습니다. WIN32의 프로세스는 운영 체제에 의해 완전히 예약됩니다. 실행 중인 프로세스의 시간 조각이 끝나면 운영 체제는 프로세스가 여전히 데이터를 처리하고 있는지 여부에 관계없이 다음 프로세스로 적극적으로 전환합니다. 엄밀히 말하면 16비트 Windows 운영 체제는 완전한 운영 체제라고 볼 수 없지만 32비트 WIN32 운영 체제가 진정한 운영 체제입니다. 물론 마이크로소프트는 WIN32가 16비트 윈도우의 단점을 보완했다고는 말하지 않을 것이며, WIN32가 상업적인 방식인 '선점형 멀티태스킹'이라는 고급 기술을 구현했다고 주장한다.
공간 관점에서 볼 때 16비트 Windows 운영 체제의 프로세스 공간은 상대적으로 독립적이지만 프로세스는 서로의 데이터 공간에 쉽게 액세스할 수 있습니다. 이러한 프로세스는 실제로 동일한 물리적 공간에 있는 서로 다른 데이터 세그먼트이기 때문에 부적절한 주소 작업으로 인해 잘못된 공간 읽기 및 쓰기가 쉽게 발생하고 운영 체제가 중단될 수 있습니다. 그러나 WIN32 운영 체제에서는 각 프로세스 공간이 완전히 독립적입니다. WIN32는 각 프로세스에 최대 4G의 가상 연속 주소 공간을 제공합니다. 소위 연속 주소 공간은 각 프로세스가 16비트 Windows의 세그먼트화된 공간이 아닌 $00000000에서 $FFFFFFFF까지의 주소 공간을 갖는 것을 의미합니다. WIN32에서는 읽기 및 쓰기 작업이 의도치 않게 다른 프로세스 공간의 데이터에 영향을 미치는 것에 대해 걱정할 필요가 없으며 작업을 방해하는 다른 프로세스에 대해 걱정할 필요도 없습니다. 동시에 WIN32가 프로세스를 위해 제공하는 지속적인 4G 가상 공간은 하드웨어 지원을 통해 운영 체제에 의해 매핑된 물리적 메모리입니다. 이렇게 방대한 가상 공간이 있더라도 시스템은 결코 1바이트를 낭비하지 않습니다. .물리적 기억.
섹션 2 프로세스 공간
DELPHI를 사용하여 WIN32 애플리케이션을 작성할 때 실행 중인 프로세스의 내부 세계에 대해서는 거의 신경 쓰지 않습니다. WIN32는 우리 프로세스에 4G의 연속 가상 프로세스 공간을 제공하기 때문에 아마도 현재 세계에서 가장 큰 응용 프로그램은 그 중 일부만 사용하고 있을 것입니다. 프로세스 공간은 무제한인 것처럼 보이지만 4G 프로세스 공간은 가상이기 때문에 여러분이 사용하는 머신의 실제 메모리는 이와 거리가 멀 수 있습니다. 프로세스의 공간이 매우 넓음에도 불구하고 일부 복잡한 알고리즘 프로그램, 특히 많은 수의 재귀 알고리즘을 포함하는 프로그램은 스택 오버플로로 인해 여전히 실행될 수 없습니다.
따라서 4G 프로세스 공간의 구조, 물리적 메모리와의 관계 등에 대한 심층적인 이해는 WIN32의 시공간 세계를 보다 명확하게 이해하는 데 도움이 되며 실제 개발 작업에서 올바른 방법을 사용할 수 있습니다. .다양한 난제를 해결하기 위한 세계관과 방법론.
다음으로, WIN32 프로세스 공간의 내부 세계를 이해하기 위해 간단한 실험을 사용하겠습니다. 이를 위해서는 CUP 레지스터와 어셈블리 언어에 대한 지식이 필요할 수 있지만 간단한 언어로 설명하려고 노력했습니다.
DELPHI가 시작되면 Project1 프로젝트가 자동으로 생성되며 이를 시작하겠습니다. Project1.dpr의 원본 프로그램 어디든 중단점을 설정합니다. 예를 들어 시작 문장에 중단점을 설정합니다. 그런 다음 프로그램을 실행하면 중단점에 도달하면 자동으로 중지됩니다. 이때 디버깅 도구에서 CPU 창을 열어 프로세스 공간의 내부 구조를 관찰할 수 있습니다.
현재 명령어 포인터 레지스터 Eip는 $0043E4B8에서 정지된다. 프로그램 명령어가 위치한 주소의 상위 2자리 16진수가 모두 0이므로 현재 프로그램이 4G의 하단 주소 위치에 있음을 알 수 있다. $00000000를 차지하는 프로세스 공간에서 $FFFFFFFF에 대한 꽤 작은 주소 공간까지.
CPU 창의 명령 상자에서 프로세스 공간의 내용을 조회할 수 있습니다. $00400000 미만의 공간 내용을 보면 $00400000 미만의 내용에 일련의 물음표 "????"가 나타나는 것을 볼 수 있습니다. 이는 주소 공간이 실제 물리적 공간에 매핑되지 않았기 때문입니다. 이때 전역변수 HInstance의 16진수 값을 살펴보면 역시 $00400000임을 알 수 있다. HInstance는 프로세스 인스턴스의 핸들을 반영하지만 실제로는 16비트 Windows에서도 프로그램이 메모리에 로드될 때 시작 주소 값입니다. 따라서 해당 프로세스의 프로그램은 $00400000부터 로딩된다고 볼 수 있다. 즉, 4G 가상공간에서 4M부터 시작하는 공간이 프로그램이 로딩되는 공간이라고 볼 수 있다.
$00400000부터 $0044D000 이전까지는 주로 프로그램 코드와 전역 데이터의 주소 공간입니다. CPU 창의 스택 상자에서 현재 스택의 주소를 볼 수 있습니다. 마찬가지로 현재 스택 주소 공간은 $0067B000부터 $00680000까지이고 길이는 $5000입니다. 실제로 프로세스의 최소 스택 공간 크기는 $5000이며, 이는 DELPHI 프로그램을 컴파일할 때 ProjectOptions의 링커 페이지에 설정된 최소 스택 크기 값에 $1000를 더한 값을 기준으로 구한 값입니다. 스택은 상위 주소에서 하위로 증가합니다. 프로그램이 실행 중일 때 스택이 충분하지 않으면 시스템은 자동으로 하위 주소로 스택 공간의 크기를 늘립니다. 프로세스 공간. DELPHI 프로그램을 컴파일할 때 ProjectOptions의 링커 페이지에서 최대 스택 크기 값을 설정하여 늘릴 수 있는 최대 스택 공간을 제어할 수 있습니다. 특히 깊은 서브루틴 호출 관계를 포함하거나 재귀 알고리즘을 사용하는 프로그램에서는 최대 스택 크기 값을 합리적으로 설정해야 합니다. 서브루틴을 호출하려면 스택 공간이 필요하고 스택이 모두 소진된 후 시스템에서 "스택 오버플로" 오류가 발생합니다.
스택 공간 다음의 프로세스 공간은 여유 공간이어야 할 것 같습니다. 실제로 WIN32 관련 정보에는 $80,000,000 이후의 2G 공간이 시스템에서 사용되는 공간이라고 나와 있습니다. 프로세스가 실제로 2G 공간만 소유할 수 있는 것으로 보입니다. 실제로 프로세스가 실제로 소유할 수 있는 공간은 2G도 아닙니다. $00000000에서 $00400000까지의 4M 공간도 제한 영역이기 때문입니다.
그러나 무슨 일이 있어도 우리 프로세스에서 사용할 수 있는 주소는 여전히 매우 광범위합니다. 특히 스택 공간 다음으로 $80,000,000 사이는 프로세스 공간의 주요 전쟁터입니다. 시스템에서 프로세스에 의해 할당된 메모리 공간이 이 공간에 매핑되고, 프로세스에 의해 로드된 동적 링크 라이브러리가 이 공간에 매핑되며, 새 스레드의 스레드 스택 공간도 이 공간에 매핑됩니다. 메모리 할당과 관련된 작업은 모두 이 공간에 매핑됩니다. 여기서 언급하는 매핑은 실제 메모리와 이 가상 공간 사이의 대응을 의미하며, 디버깅 중 CPU 창의 명령 상자에 있는 "" 문자열과 마찬가지로 실제 메모리에 매핑되지 않은 프로세스 공간은 사용할 수 없습니다. ???".
............
읽어주셔서 감사합니다!