이 기사에서는 주로 Java 메모리 할당의 스택, 힙 및 상수 풀을 분석하여 작동 원리를 자세히 설명합니다.
1. 자바 가상 머신 메모리 프로토타입
레지스터(Register): 프로그램에 대한 제어권이 없습니다. 스택(Stack): 기본 유형의 데이터 및 개체 참조를 저장하지만 개체 자체는 스택에 저장되지 않고 힙(Heap)에 저장됩니다. : 객체에 저장됩니다. static: 상수를 저장하는 정적 멤버 상수 풀입니다. 비 RAM 저장소: 하드 디스크와 같은 영구 저장 공간입니다.
2. 상수 풀
상수 풀은 컴파일 타임에 결정되어 컴파일된 메모리에 저장되는 상수 풀을 의미합니다. 클래스 파일의 일부 데이터. 코드에 정의된 다양한 기본 유형(예: int, long 등)과 객체 유형(예: 문자열 및 배열)이 포함된 상수 값(최종) 외에도 텍스트 형식의 일부 기호 참조도 포함되어 있습니다. , 와 같은:
1. 클래스 및 인터페이스의 정규화된 이름
2. 필드 이름 및 설명자
3. 방법, 이름 및 설명자.
가상 머신은 로드된 각 유형에 대해 상수 풀을 유지해야 합니다. 상수 풀은 직접 상수(문자열, 정수 및 부동 소수점 상수)와 다른 유형, 필드 및 메소드에 대한 기호 참조를 포함하여 이 유형에서 사용되는 순서화된 상수 세트입니다. 문자열 상수의 경우 해당 값은 상수 풀에 있습니다. JVM의 상수 풀은 메모리에 테이블 형식으로 존재합니다. 문자열 유형의 경우 리터럴 문자열 값을 저장하는 데 사용되는 고정 길이 CONSTANT_String_info 테이블이 있습니다. 참고: 이 테이블은 기호가 아닌 리터럴 문자열 값만 저장합니다. . 이렇게 말하면 상수 풀에서 문자열 값의 저장 위치를 명확하게 이해해야 합니다. 프로그램이 실행되면 상수 풀은 힙이 아닌 메소드 영역에 저장됩니다.
3. Java 메모리 할당 스택
스택의 기본 단위는 프레임(또는 스택 프레임)입니다. Java 스레드가 실행될 때마다 Java 가상 머신은 해당 스레드에 Java 스택을 할당합니다. 스레드가 특정 Java 메소드를 실행할 때 프레임을 Java 스택에 푸시합니다. 이 프레임은 매개변수, 지역 변수, 피연산자, 중간 연산 결과 등을 저장하는 데 사용됩니다. 이 메서드의 실행이 완료되면 프레임이 스택에서 팝됩니다. Java 스택의 모든 데이터는 비공개이며 다른 스레드는 스레드의 스택 데이터에 액세스할 수 없습니다. 함수에 정의된 일부 기본 유형의 변수 데이터와 객체 참조 변수는 함수의 스택 메모리에 할당됩니다. 변수가 코드 블록에 정의되면 Java는 변수가 범위를 벗어날 때 변수에 대한 메모리 공간을 스택에 할당합니다. Java는 변수에 할당된 메모리 공간을 자동으로 해제하고 메모리 공간을 즉시 사용할 수 있습니다. 다른 목적으로 사용될 수 있습니다.
4. Java 메모리 할당의 힙
JVM(Java Virtual Machine)의 힙은 new로 생성된 객체와 배열을 저장하는 데 사용됩니다. 힙에 할당된 메모리는 JVM(Java Virtual Machine)의 자동 가비지 수집 메커니즘에 의해 관리됩니다. 쉽게 말하면 스택에 비해 힙은 주로 자바 객체를 저장하는 데 사용되고, 스택은 주로 객체 참조를 저장하는 데 사용된다... 힙에 배열이나 객체가 생성된 후에는 특수 변수도 사용할 수 있다. 스택에 있는 이 변수의 값은 힙 메모리에 있는 배열이나 개체의 첫 번째 주소와 동일하도록 스택에 정의됩니다. 스택에 있는 이 변수는 배열이나 개체의 참조 변수가 됩니다. 참조 변수는 배열이나 개체에 이름을 지정하는 것과 같습니다. 그런 다음 스택의 참조 변수를 사용하여 프로그램의 힙에 있는 배열이나 개체에 액세스할 수 있습니다. 참조 변수는 배열이나 객체에 이름을 지정하는 것과 같습니다.
참조 변수는 정의 시 스택에 할당되는 일반 변수입니다. 참조 변수는 프로그램이 해당 범위 외부에서 실행된 후에 해제됩니다. 배열과 객체 자체는 힙에 할당됩니다. 배열이나 객체를 생성하기 위해 new를 사용하는 명령문이 있는 코드 블록 외부에서 프로그램이 실행되더라도 배열과 객체 자체가 차지하는 메모리는 해제되지 않습니다. 객체에 자신을 가리키는 참조 변수가 없으면 가비지가 되어 더 이상 사용할 수 없지만 여전히 메모리 공간을 차지하고 나중에 불확실한 시간에 가비지 수집기에 의해 수집(해제)됩니다. 이는 Java가 더 많은 메모리를 차지하는 이유이기도 합니다. 실제로 스택의 변수는 힙 메모리의 변수를 가리킵니다. 이는 Java의 포인터입니다.
Java의 힙은 클래스 객체가 공간을 할당하는 런타임 데이터 영역입니다. 이러한 객체는 new, newaray, anewarray 및 multianewarray와 같은 명령을 통해 생성되며 가비지 수집을 통해 명시적으로 해제되는 프로그램 코드가 필요하지 않습니다. 책임 있는 힙의 장점은 메모리 크기를 동적으로 할당할 수 있다는 점이며 런타임에 메모리를 동적으로 할당하고 Java의 가비지 수집기가 더 이상 사용되지 않는 메모리를 자동으로 수집하기 때문에 수명을 컴파일러에 미리 알릴 필요가 없다는 것입니다. 하지만 단점은 런타임에 메모리를 동적으로 할당해야 하기 때문에 접근 속도가 느리다는 점입니다.
스택의 장점은 힙에 비해 레지스터 다음으로 접근 속도가 빠르고, 스택 데이터를 공유할 수 있다는 점이다. 하지만 스택에 저장되는 데이터의 크기와 수명을 결정해야 하고 유연성이 부족하다는 점이 단점이다. 스택은 주로 몇 가지 기본 유형의 변수 데이터(int, short, long, byte, float, double, boolean, char)와 객체 핸들(참조)을 저장합니다.
스택의 매우 중요한 특수 기능은 스택에 저장된 데이터를 공유할 수 있다는 것입니다. 다음도 정의한다고 가정해 보겠습니다.
int a=3; int b=3; 컴파일러는 먼저 int a = 3을 처리하여 스택에 변수 a에 대한 참조를 만든 다음 스택에 값 3이 있는지 확인합니다. 3을 설정한 다음 a를 3으로 지정합니다. 그런 다음 b의 참조 변수를 만든 후 int b = 3을 처리합니다. 스택에 이미 3의 값이 있으므로 b는 직접 3을 가리킵니다. 이와 같이 a와 b가 동시에 등장하여 둘 다 3의 경우를 가리킨다.
이때 a=4가 다시 설정되면 컴파일러는 스택에 4 값이 있는지 다시 검색합니다. 그렇지 않으면 4를 저장하고 이미 존재하는 경우 이를 가리킵니다. 이 주소를 직접 가리킵니다. 따라서 a 값의 변화는 b 값에 영향을 미치지 않습니다.
이러한 종류의 데이터 공유는 동시에 하나의 객체를 가리키는 두 객체의 참조를 공유하는 것과 다르다는 점에 유의해야 합니다. 이 경우 a의 수정은 b에 영향을 미치지 않고 컴파일러에 의해 완료되기 때문입니다. 공간을 절약하는 데 도움이 됩니다. 개체 참조 변수가 개체의 내부 상태를 수정하면 다른 개체 참조 변수에 영향을 미칩니다.