>  기사  >  Java  >  Java 메모리 영역 및 메모리 오버플로 예외에 대한 자세한 소개

Java 메모리 영역 및 메모리 오버플로 예외에 대한 자세한 소개

黄舟
黄舟원래의
2017-03-17 10:18:411250검색

이 글에서는 Java 메모리 영역 및 메모리 오버플로 예외에 대한 관련 정보를 주로 소개합니다. 필요한 친구는

Java 메모리 영역 및 메모리 오버플로 예외

를 참고하세요. 개요

C 및 C++ 프로그램 개발 개발자의 경우, 메모리 관리 분야에서 프로그래머는 메모리 사용에 대한 절대적인 권리를 가지지만, 가장 중요한 것은 메모리를 올바르게 사용하고 정리하려면 프로그래머의 수준이 높아야 합니다.

Java 프로그래머의 경우 가상 머신의 자동 메모리 관리 메커니즘 덕분에 새로운 작업마다 삭제/해제 코드 쌍을 작성할 필요가 없으며 메모리 누수 및 메모리 오버플로 문제가 발생하는 것 같습니다. 메모리를 관리하는 가상 머신에서는 모든 것이 정상입니다. 그러나 이는 Java 프로그래머가 Java 가상 머신에 메모리 제어 권한을 부여했기 때문입니다. 메모리 누수 및 오버플로 문제가 발생하면 가상 머신이 메모리를 어떻게 사용하는지 이해하지 못하면 오류 문제 해결이 매우 중요해집니다. 어려운 일.

Java 런타임 데이터 영역

일반적으로 JVM은 힙과 스택 두 부분으로만 구성되어 있다고 생각하지만 실제 Java 가상 머신은 Java를 실행합니다. 프로그램이 관리하는 메모리는 여러 다른 데이터 영역으로 나뉩니다. 이러한 영역에는 고유한 목적과 생성 및 소멸 시점이 있으며, 일부 영역은 가상 머신 프로세스 시작과 함께 존재하고 일부 영역은 사용자 스레드의 시작 및 종료에 따라 생성 및 소멸됩니다. 아래와 같이

프로그램 카운터

컴퓨터 구성의 원리를 공부했다면 프로그램이 카운터는 ID 카드와 동일합니다. 마찬가지로 JVM에도 자체 CPU가 있으므로 멀티 스레드 프로그램을 실행할 때 타임 슬라이스 회전을 통해 프로그램 카운터에 따라 스레드 실행을 예약합니다.

프로그램 카운터 레지스터는 작은 메모리 공간으로, 그 기능은 현재 스레드에서 실행되는 바이트코드의 줄 번호 표시기로 간주될 수 있습니다. 가상 머신의 개념적 모델(단지 개념적 모델일 뿐이며 다양한 가상 머신이 보다 효율적인 방식으로 구현될 수 있음)에서 바이트코드 인터프리터는 이 카운터 값을 변경하여 실행해야 하는 다음 단계를 선택하고 분기합니다. , 루프, 점프, 예외 처리, 스레드 복구 및 기타 기본 기능은 모두 이 카운터를 사용하여 완료해야 합니다.

Java Virtual Machine의 멀티스레딩은 스레드를 차례로 전환하고 프로세서 실행 시간을 할당하여 구현되므로 특정 순간에 프로세서(멀티코어 프로세서의 경우 코어)는 실행만 수행합니다. 하나의 스레드에 지침이 있습니다. 따라서 스레드 전환 후 올바른 실행 위치로 돌아가기 위해서는 각 스레드마다 독립적인 프로그램 카운터가 있어야 합니다. 각 스레드 간의 카운터는 서로 영향을 주지 않으며 독립적으로 저장됩니다. ". "메모리.

스레드가 Java 메소드를 실행하는 경우 이 카운터는 실행 중인 가상 머신 바이트코드 명령의 주소를 기록합니다. 스레드가 Natvie 메소드를 실행하는 경우 카운터 값은 비어 있습니다(정의되지 않음). 이 메모리 영역은 Java Virtual Machine 사양이 OutOfMemoryError 조건을 지정하지 않는 유일한 영역입니다.

Java Virtual Machine Stack

프로그램 카운터와 마찬가지로 Java Virtual Machine 스택도 스레드 전용이며 수명 주기스레딩과 동일합니다. .

가상 머신 스택은 Java 메소드 실행의 메모리 모델을 설명합니다. 각 메소드가 실행될 때 스택 프레임(스택 프레임)이 동시에 생성되어 로컬 변수 테이블, 작업 스택, 동적 링크, 메서드 내보내기 및 기타 정보. 각 메서드가 호출되어 실행이 완료될 때까지의 과정은 가상 머신 스택의 스택 프레임이 스택에서 푸시되어 스택 밖으로 튀어나오는 과정에 해당합니다.

자바 메모리를 힙 메모리(Heap)와 스택 메모리(Stack)로 나누는 경우가 많습니다. 이 구분은 실제로는 이보다 훨씬 복잡합니다. 이 분할 방법의 인기는 대부분의 프로그래머가 가장 주의를 기울이고 객체 메모리 할당과 가장 밀접하게 관련된 메모리 영역이 이 두 영역이라는 것을 보여줍니다. 언급되는 "힙"에 대해서는 나중에 구체적으로 설명할 것이며, 언급하는 "스택"은 지금 우리가 이야기하고 있는 가상 머신 스택, 즉 가상 머신 스택의 로컬 변수 테이블 부분을 의미합니다.

지역 변수 테이블은 다양한 기본 데이터 유형(boolean, byte, char, short, int, float, long, double), 객체 참조(참조 유형, 객체 자체와 동일하지 않습니다. 다른 가상 머신 구현에 따라 객체의 시작 주소를 가리키는 참조 포인터일 수도 있고 객체 또는 이 객체와 관련된 다른 위치를 나타내는 핸들을 가리킬 수도 있습니다. (바이트코드 명령어의 주소를 가리킨다).

64비트 long형과 double형 데이터는 지역변수 공간(Slot) 2개를 차지하고, 그 외 데이터형은 1개만 차지합니다. 지역 변수 테이블에 필요한 메모리 공간은 메소드를 입력할 때 할당됩니다. 이 메소드가 프레임에 할당해야 하는 지역 변수 공간의 크기는 실행 중에 변경되지 않습니다. 방법의.

Java 가상 머신 사양에서는 이 영역에 대해 두 가지 예외 조건이 지정됩니다. 스레드에서 요청한 스택 깊이가 가상 머신에서 허용하는 깊이보다 크면 StackOverflowError 예외가 발생합니다. 가상 머신 스택은 동적으로 확장될 수 있습니다. (대부분의 JVM(Java Virtual Machine)은 동적으로 확장될 수 있지만 JVM(Java Virtual Machine) 사양에서는 고정 길이 가상 머신 스택도 허용합니다.) 충분한 메모리를 확보하기 위해 확장을 적용할 수 없으면 OutOfMemoryError 예외가 발생합니다.

네이티브 메서드 스택

네이티브 메서드 스택(네이티브 메서드 스택)과 가상 머신 스택이 수행하는 기능은 가상 머신 스택이 매우 유사하다는 점뿐입니다. 가상 머신은 Java 메소드(즉, 바이트코드) 서비스를 실행하고 로컬 메소드 스택은 가상 머신에서 사용하는 기본 메소드를 제공합니다. 가상 머신 사양은 로컬 메소드 스택의 메소드 언어, 사용법, 데이터 구조를 요구하지 않으므로 특정 가상 머신이 자유롭게 구현할 수 있습니다. 일부 가상 머신(예: Sun HotSpot 가상 머신)은 로컬 메소드 스택과 가상 머신 스택을 하나로 직접 결합하기도 합니다. 가상 머신 스택과 마찬가지로 로컬 메서드 스택 영역에서도 StackOverflowError 및 OutOfMemoryError 예외가 발생합니다.

Java 힙

대부분의 애플리케이션에서 Java 힙(Java Heap)은 Java 가상 머신이 관리하는 가장 큰 메모리 부분입니다. Java 힙은 모든 스레드가 공유하는 메모리 영역으로 가상 머신이 시작될 때 생성됩니다. 이 메모리 영역의 유일한 목적은 객체 인스턴스를 저장하는 것이며 거의 모든 객체 인스턴스가 여기에 메모리를 할당합니다. 이는 Java Virtual Machine 사양에 다음과 같이 기술되어 있습니다. 모든 객체 인스턴스와 배열은 힙에 할당되어야 합니다. 그러나 JIT 컴파일러의 발전과 이스케이프 분석 기술의 점진적인 성숙으로 인해 스택에 대한 할당 및 스칼라 대체 최적화 기술이 적용됩니다. will 이로 인해 약간의 미묘한 변화가 발생하고 힙에 할당된 모든 개체는 점차 덜 "절대적"이 됩니다.

ava 힙은 가비지 컬렉터가 관리하는 주요 영역이므로 "GC 힙(" Garbage Collected Heap, 다행히 중국에서는 "쓰레기 힙")으로 번역되지 않음)이라고도 합니다. 메모리 재활용의 관점에서 볼 때, 현재 수집기는 기본적으로 세대별 수집 알고리즘을 사용하므로 Java 힙은 다음과 같이 세분화될 수도 있습니다. 신세대와 구세대, 더 자세한 세대에는 Eden 공간, From Survivor 공간, To Survivor 공간 등이 포함됩니다. 메모리 할당의 관점에서 스레드 공유 Java 힙은 여러 스레드 전용 할당 버퍼(Thread Local Allocation Buffer, TLAB)로 분할될 수 있습니다. 그러나 어떻게 분할하든 저장 내용과는 아무런 관련이 없으며, 어떤 영역에 있든 객체 인스턴스는 여전히 저장됩니다. 이 장에서는 메모리 영역의 역할에 대해서만 설명하며, Java 힙에서 위 영역의 할당 및 재활용에 대한 자세한 내용은 다음 장에서 다루겠습니다.

Java Virtual Machine 사양에 따르면 Java 힙은 디스크 공간과 마찬가지로 논리적으로 연속적인 한 물리적으로 불연속적인 메모리 공간에 있을 수 있습니다. 구현 시 고정 크기 또는 확장 가능으로 구현될 수 있지만 현재 주류 가상 머신은 모두 확장 가능(-Xmx 및 -Xms에 의해 제어)으로 구현됩니다. 힙에 인스턴스 할당을 완료할 메모리가 없고 힙을 더 이상 확장할 수 없는 경우 OutOfMemoryError 예외가 발생합니다.

메서드 영역

메서드 영역은 Java 힙과 마찬가지로 각 스레드가 공유하는 메모리 영역으로 가상으로 로드된 클래스를 저장하는 데 사용됩니다. machine.정보, 상수, 정적 변수, 적시 컴파일러로 컴파일된 코드 및 기타 데이터입니다. Java Virtual Machine 사양에서는 메서드 영역을 힙의 논리적 부분으로 설명하지만 여기에는 Non-Heap(비힙)이라는 별칭이 있어 Java 힙과 구별되어야 합니다.

Java 가상 머신 사양에는 이 영역에 대한 제한이 매우 느슨합니다. Java 힙과 같은 연속 메모리가 필요하지 않고 고정 크기 또는 확장성 옵션이 있는 것 외에도 가비지 수집을 구현하지 않도록 선택할 수도 있습니다. 이 영역에서는 상대적으로 가비지 컬렉션 동작이 상대적으로 드물지만, 영구 생성 이름처럼 데이터가 메소드 영역에 들어가서 "영구적으로" 존재한다는 의미는 아닙니다. 이 영역의 메모리 재활용 목표는 주로 상수 풀 재활용 및 유형 언로드에 대한 것입니다. 일반적으로 이 영역의 재활용 "점수"는 상대적으로 만족스럽지 않으며 특히 유형 언로드의 경우 조건이 매우 가혹합니다. 재활용은 실제로 필요합니다.

Java Virtual Machine 사양에 따라 메소드 영역이 메모리 할당 요구 사항을 충족할 수 없는 경우 OutOfMemoryError 예외가 발생합니다.

런타임 상수 풀

런타임 상수 풀은 메소드 영역의 일부입니다. 클래스 버전, 필드, 메소드, 인터페이스 및 기타 설명과 같은 정보 외에도 클래스 파일에는 컴파일 중에 생성된 다양한 리터럴을 저장하는 데 사용되는 상수 풀(상수 풀 테이블)도 포함되어 있습니다. 클래스가 로드된 후 메서드 영역의 런타임 상수 풀에 저장되는 기호 참조입니다.

Java 가상 머신에는 클래스 파일의 각 부분(당연히 상수 풀 포함)의 형식에 대한 엄격한 규정이 있습니다. 각 바이트는 사양 요구 사항을 준수해야 하는 데이터 종류를 저장하는 데 사용되어야 합니다. 이는 가상 머신에 의해 인식, 로드 및 실행됩니다. 그러나 런타임 상수 풀의 경우 JVM(Java Virtual Machine) 사양은 세부적인 요구 사항을 제시하지 않습니다. 다양한 공급자가 구현한 가상 머신은 자체 요구 사항에 따라 이 메모리 영역을 구현할 수 있습니다. 그러나 일반적으로 클래스 파일에 설명된 기호 참조를 저장하는 것 외에도 번역된 직접 참조도 런타임 상수 풀에 저장됩니다.

클래스 파일 상수 풀과 비교하여 런타임 상수 풀의 또 다른 중요한 특징은 Java 언어에서는 컴파일 중에만 상수를 생성할 필요가 없다는 것입니다. 클래스 파일. 풀의 내용만 메서드 영역의 런타임 상수 풀에 들어갈 수 있습니다. 런타임 중에 새 상수를 풀에 넣을 수도 있습니다. 이 기능은 String의 intern()입니다. 수업 방법.

런타임 상수 풀은 메소드 영역의 일부이므로 자연스럽게 메소드 영역의 메모리에 의해 제한됩니다. 상수 풀이 더 이상 메모리를 적용할 수 없으면 OutOfMemoryError 예외가 발생합니다.

다이렉트 메모리

다이렉트 메모리(Direct Memory)는 가상 머신 런타임 데이터 영역의 일부도 아니고, Java Virtual Machine 사양에 정의된 메모리 영역도 아닙니다. , 그러나 이 메모리 부분도 자주 사용되며 OutOfMemoryError 예외가 발생할 수도 있습니다.

JDK 1.4에는 NIO(New Input/Output) 클래스가 추가되었으며, 채널 및 버퍼 기반의 I/O 방식이 도입되었습니다. 네이티브 함수 라이브러리를 직접 사용할 수 있습니다. 오프힙 메모리를 할당합니다. , 이 메모리에 대한 참조로 Java 힙에 저장된 DirectByteBuffer 개체를 통해 작동합니다. 이렇게 하면 Java 힙과 기본 힙 간에 데이터가 앞뒤로 복사되는 것을 방지하므로 일부 시나리오에서 성능이 크게 향상될 수 있습니다.

분명히 로컬 직접 메모리 할당은 Java 힙 크기에 의해 제한되지 않습니다. 그러나 메모리이므로 전체 로컬 메모리(RAM 및 힙 포함)의 크기에 의해 영향을 받습니다. SWAP 영역 또는 페이징 파일). 서버 관리자가 가상 ​​머신 매개변수를 구성할 때 일반적으로 실제 메모리를 기준으로 -Xmx 및 기타 매개변수 정보를 설정하지만 직접 메모리를 무시하는 경우가 많아 각 메모리 영역의 합이 물리적 메모리 제한(물리적 및 운영 체제 수준 포함)보다 크게 됩니다. 제한)), 동적 확장 중에 OutOfMemoryError 예외가 발생합니다.

위 내용은 Java 메모리 영역 및 메모리 오버플로 예외에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.