>  기사  >  Java  >  힙이란 무엇입니까? 메소드 영역은 무엇인가요? JVM 메모리 모델의 힙 및 메소드 영역 소개

힙이란 무엇입니까? 메소드 영역은 무엇인가요? JVM 메모리 모델의 힙 및 메소드 영역 소개

不言
不言원래의
2018-09-15 17:43:0411941검색

이 글의 내용은 힙이 무엇인지에 관한 것입니다. 메소드 영역은 무엇인가요? JVM 메모리 모델의 힙 및 메소드 영역 도입에는 특정 참조 값이 있으므로 도움이 필요한 친구가 참고할 수 있기를 바랍니다.

1. 힙

1.1 힙이란 객체를 저장하는 데 사용되는 메모리 영역입니다. 따라서 가비지 컬렉터(GC) 관리의 주요 대상이다.

    힙은 논리적으로 "신세대"와 "구세대"로 구분됩니다. JAVA의 대부분의 객체는 태어나고 소멸되며 소수는 오랫동안 메모리에 남아 있을 수 있으므로 이 두 객체의 가장 효과적인 재활용을 달성하기 위해 힙을 신세대와 구세대로 구분합니다. 생성 및 실행은 재활용 전략이 다릅니다. 서로 다른 가비지 수집기는 이 두 가지 논리적 영역에 대해 서로 다른 재활용 메커니즘을 가지고 있으며 이에 대해서는 후속 장에서 자세히 설명합니다.
  • 힙이 차지하는 메모리에는 물리적 연속성이 필요하지 않고 논리적 연속성만 필요합니다.
  • 힙은 일반적으로 확장 가능한 메모리 크기로 구현됩니다. "-Xms" 및 "-Xmx"를 사용하여 힙의 최소 및 최대 메모리를 제어하고 확장 작업은 가상 머신에서 수행됩니다. 그러나 이 동작은 성능을 소모하므로 일반적으로 힙의 최대 메모리와 최소 메모리는 동일하게 설정됩니다.
  • 힙은 모든 스레드가 공유하는 메모리 영역이므로 각 스레드는 힙에서 동일한 개체를 얻을 수 있습니다.
  • 가상 머신이 시작될 때 힙의 수명 주기가 생성됩니다.

1.2.힙 예외

 힙이 개체 메모리를 할당할 수 없어 더 이상 확장할 수 없으면 OutOfMemoryError 예외가 발생합니다.


일반적으로 힙이 객체를 할당할 수 없을 때 GC가 수행됩니다. GC 후에도 객체를 할당할 수 없으면 메모리 소모 오류가 보고됩니다. 이 상황은 참조를 해제하지 않고 지속적으로 새 개체를 생성하여 시뮬레이션할 수 있습니다.

/**
 * java堆溢出demo
 * JVM参数:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 * Created by chenjunyi on 2018/4/25.
 */
public class HeapOOM {

    static class OOMObject {
    }

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<>();
        //不断创建新对象,使得Heap溢出
        while (true) {
            list.add(new OOMObject());
        }
    }

}

위 코드에서 개체는 참조를 해제하지 않고 계속 생성되어 GC가 힙 메모리를 회수할 수 없게 되고 궁극적으로 OutOfMemoryError 오류 메시지가 발생합니다.

java.lang.OutOfMemoryError: Java heap space

2. 메소드 영역

2.1. 메소드 영역이란


  비힙(Non-Heap)이라고도 불리는 메소드 영역은 스레드가 공유하는 또 다른 메모리 영역입니다. 주로 로드된 클래스 바이트코드, 클래스/메서드/필드 및 기타 메타데이터 개체, 정적 최종 상수, 정적 변수, JIT 컴파일러로 컴파일된 코드 및 기타 데이터를 저장합니다. 또한 메소드 영역에는 "런타임 상수 풀"이라는 특수 영역이 포함되어 있으며 이들의 관계는 아래 그림에 나와 있습니다.


(1) 로드된 클래스 바이트코드: 클래스를 사용하려면 먼저 바이트코드가 필요합니다. JVM의 메모리에 로드됩니다. 클래스 바이트코드의 소스는 .class 파일, 네트워크 전송 또는 cglib 바이트코드 프레임워크에 의해 직접 생성되는 등 다양할 수 있습니다.

(2) 클래스/메서드/필드와 같은 메타데이터 개체: 바이트코드가 로드된 후 JVM은 콘텐츠를 기반으로 이 클래스에 대한 클래스/메서드/필드 및 기타 개체를 생성합니다. 일반적으로 클래스를 설명하는 데 사용됩니다. 반사가 더 자주 사용됩니다. 힙에 저장된 Java 인스턴스 객체와 달리 이 두 객체는 ​​메서드 영역에 저장됩니다.

(3) 정적 최종 상수 및 정적 변수: 이 두 가지 유형의 클래스 멤버에 대해 JVM은 메서드 영역에 데이터 복사본을 생성하므로 동일한 정적 수정 클래스 멤버의 복사본은 하나만 있습니다. class;
(4) JIT 컴파일러의 컴파일 결과: 핫스팟 가상 머신을 예로 들면 JIT JIT 컴파일러를 사용하여 런타임 중에 핫스팟 코드를 최적화하는 것입니다. 기계어 코드. 일반적으로 JVM은 "해석 및 실행" 방법을 사용하여 바이트코드를 실행합니다. 즉, JVM이 바이트코드 명령어를 읽을 때 미리 결정된 규칙에 따라 스택 작업을 수행하고 스택 작업은 기본 Machine 작업에 추가로 매핑됩니다. ; JIT 컴파일 후 실행된 기계어 코드는 기본 기계를 직접 처리합니다. 아래 그림과 같이:

2.2. 런타임 상수 풀

섹션 2.1에서 우리는 클래스의 바이트코드가 로드될 때 파싱되고 다양한 것을 생성하여 메소드 영역에 저장한다는 것을 배웠습니다. . 클래스의 바이트코드에는 클래스 버전, 필드, 메서드, 인터페이스 등과 같은 설명 정보가 포함될 뿐만 아니라 상수 풀도 포함됩니다. 상수 풀은 바이트 코드에 사용되는 모든 리터럴 및 기호 참조(예: 문자열 리터럴)를 저장하는 데 사용됩니다. 클래스가 로드되면 저장을 위해 메서드 영역에 런타임 상수 풀을 입력합니다.

  런타임 상수 풀은 메소드 영역의 특별한 부분이며 동적입니다. 즉, 클래스가 로드될 때 상수 풀을 여기에 쓰는 것 외에도 실행 중에도 상수를 쓸 수 있습니다. Java 프로그램:

1 //使用StringBuilder在堆上创建字符串abc,再使用intern将其放入运行时常量池
2 String str = new StringBuilder("abc");
3 str.intern();
4 //直接使用字符串字面量xyz,其被放入运行时常量池
5 String str2 = "xyz";

2.3. 메소드 영역 구현

 가상 머신 사양에는 메소드 영역 구현이 명확하게 규정되어 있지 않습니다. 현재 두 가지 주요 구현 방법이 있습니다.

(1)HotSpot虚拟机1.7-:在JDK1.6及之前版本,HotSpot使用“永久代(permanent generation)”的概念作为实现,即将GC分代收集扩展至方法区。这种实现比较偷懒,可以不必为方法区编写专门的内存管理,但带来的后果是容易碰到内存溢出的问题(因为永久代有-XX:MaxPermSize的上限)。在JDK1.7+之后,HotSpot逐渐改变方法区的实现方式,如1.7版本移除了方法区中的字符串常量池。

(2)HotSpot虚拟机1.8+:1.8版本中移除了方法区并使用metaspace(元数据空间)作为替代实现。metaspace占用系统内存,也就是说,只要不碰触到系统内存上限,方法区会有足够的内存空间。但这不意味着我们不对方法区进行限制,如果方法区无限膨胀,最终会导致系统崩溃。

  我们思考一个问题,为什么使用“永久代”并将GC分代收集扩展至方法区这种实现方式不好,会导致OOM?首先要明白方法区的内存回收目标是什么,方法区存储了类的元数据信息和各种常量,它的内存回收目标理应当是对这些类型的卸载和常量的回收。但由于这些数据被类的实例引用,卸载条件变得复杂且严格,回收不当会导致堆中的类实例失去元数据信息和常量信息。因此,回收方法区内存不是一件简单高效的事情,往往GC在做无用功。另外随着应用规模的变大,各种框架的引入,尤其是使用了字节码生成技术的框架,会导致方法区内存占用越来越大,最终OOM。

2.4.方法区异常

  在2.3一节中,我们了解到方法区的2种实现方式最终都会有一个最大值上限,因此若方法区(含运行时常量池)占用内存到达其最大值,且无法再申请到内存时,便会抛出OutOfMemoryError。

  在下面的例子中,我们将使用cglib字节码生成框架不断生成新的类,最终使方法区内存占用满,抛出OutOfMemoryError:

/**
 * java方法区溢出OutOfMemoryError(JVM参数适用于JDK1.6之前,借助CGLIB)
 * JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M
 * Created by chenjunyi on 2018/4/26.
 */
public class JavaMethodAreaOOM {

    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> methodProxy.invokeSuper(objects, args));
            enhancer.create();
        }
    }

    static class OOMObject {
    }

}

报错信息为:

1 Caused by: java.lang.OutOfMemoryError: PermGen space
2   at java.lang.ClassLoader.defineClass1(Native Method)
3   ···

其实,在日常开发中,不仅仅使CGlib字节码生成框架会产生大量的class信息,动态语言、JSP、基于OSGI的应用都会在方法区额外产生大量的类信息。

위 내용은 힙이란 무엇입니까? 메소드 영역은 무엇인가요? JVM 메모리 모델의 힙 및 메소드 영역 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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