이 글의 내용은 힙이 무엇인지에 관한 것입니다. 메소드 영역은 무엇인가요? JVM 메모리 모델의 힙 및 메소드 영역 도입에는 특정 참조 값이 있으므로 도움이 필요한 친구가 참고할 수 있기를 바랍니다.
1.2.힙 예외
일반적으로 힙이 객체를 할당할 수 없을 때 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()); } } }
java.lang.OutOfMemoryError: Java heap space
2. 메소드 영역
(1) 로드된 클래스 바이트코드: 클래스를 사용하려면 먼저 바이트코드가 필요합니다. JVM의 메모리에 로드됩니다. 클래스 바이트코드의 소스는 .class 파일, 네트워크 전송 또는 cglib 바이트코드 프레임워크에 의해 직접 생성되는 등 다양할 수 있습니다.
(2) 클래스/메서드/필드와 같은 메타데이터 개체: 바이트코드가 로드된 후 JVM은 콘텐츠를 기반으로 이 클래스에 대한 클래스/메서드/필드 및 기타 개체를 생성합니다. 일반적으로 클래스를 설명하는 데 사용됩니다. 반사가 더 자주 사용됩니다. 힙에 저장된 Java 인스턴스 객체와 달리 이 두 객체는 메서드 영역에 저장됩니다.(3) 정적 최종 상수 및 정적 변수: 이 두 가지 유형의 클래스 멤버에 대해 JVM은 메서드 영역에 데이터 복사본을 생성하므로 동일한 정적 수정 클래스 멤버의 복사본은 하나만 있습니다. class;
(4) JIT 컴파일러의 컴파일 결과: 핫스팟 가상 머신을 예로 들면 JIT JIT 컴파일러를 사용하여 런타임 중에 핫스팟 코드를 최적화하는 것입니다. 기계어 코드. 일반적으로 JVM은 "해석 및 실행" 방법을 사용하여 바이트코드를 실행합니다. 즉, JVM이 바이트코드 명령어를 읽을 때 미리 결정된 규칙에 따라 스택 작업을 수행하고 스택 작업은 기본 Machine 작업에 추가로 매핑됩니다. ; JIT 컴파일 후 실행된 기계어 코드는 기본 기계를 직접 처리합니다. 아래 그림과 같이:
2.2. 런타임 상수 풀
런타임 상수 풀은 메소드 영역의 특별한 부분이며 동적입니다. 즉, 클래스가 로드될 때 상수 풀을 여기에 쓰는 것 외에도 실행 중에도 상수를 쓸 수 있습니다. 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.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 중국어 웹사이트의 기타 관련 기사를 참조하세요!