当前位置: 首页 > 后端技术 > Java

【JVM内存管理机制-第一章】java内存区与内存溢出异常

时间:2023-04-01 14:55:03 Java

运行时数据区:1.程序计数器存放当前线程下一条要执行的字节码指令的行号指示符特点:线程占用小内存唯一私有的java虚拟机规范没有指定任何OOM(OutOfMemoryError)区域。如果当前线程正在执行java方法,则计数器记录子字节码指令的地址;如果native方法正在执行,那么计数器的值为空(Undefined)思考1:为什么要设计程序计数器?Java程序的执行流程设计如下图所示。也就是将java源码编译成二进制字节码。这些二进制字节码文件中的一行一行的JVM指令(比如getstatic)被解释器一条一条解释成机器可识别的01,最后才能交付给CPU执行。当字节码被解释器解释执行时,程序计数器需要记录一条要执行的指令。思考2??:为什么要把程序计数器设计成线程私有的?由于Java虚拟机的多线程是通过轮流切换线程,分配处理器执行的做法来实现的,在任何给定的时刻,一个处理器(一个核)只能执行一个线程中的指令。因此,为了保证线程切换后能够恢复到正确的执行位置,每个线程都需要一个独立的程序计数器2.Java虚拟机栈java虚拟机栈描述了java方法执行的内存模型:每个方法都会执行时会创建一个栈帧(StackFrame),是方法运行时的基本数据结构。栈帧包括局部变量表、操作数栈、动态链接和方法出口。java虚拟机栈有两种异常情况:如果线程请求的栈深度大于虚拟机允许的深度,如果虚拟机栈设置为可动态扩展,则会抛出StackOverflowError异常。3.本地方法栈顾名思义,本地方法栈就是Native方法服务的栈结构,类似于虚拟机栈。4、java堆是java虚拟管理的最大一块内存。所有线程共享它。当虚拟机启动时,所有的对象实例和数组都被创建和存储。GC的主要区域从GC的角度可以细分为:新生代和老年代。.新生代又可以细分为:Eden区、逃逸区1、逃逸区2。从内存分配的角度来看,线程共享的Java堆可能分为多个线程私有的分配缓冲区(ThreadLoaclAllocationBuffer,TLAB)java堆区可以位于物理上不连续的内存空间。为了保证逻辑上的连续性,可以设置一个固定的大小,也可以设置为可伸缩的。如果堆中没有内存空间可供分配,无法扩展堆,则会抛出OOMError异常。5.方法区方法区和java堆一样,是各个线程共享的一块区域。用来存放虚拟机加载过的东西:类信息常量,静态变量,实时编译器编译的代码,方法区也存在OOMError异常。六、运行时常量池运行时常量池是方法区的一部分。Class文件中除了类版本、字段、方法、接口等描述信息外,还有一个信息常量池,称为Class文件常量池。用于存放编译过程中产生的各种字面量和符号引用,这部分信息在类加载后进入方法区,形成运行时常量池。字面量相当于Java语言层面的常量概念,如文本字符串、声明为final的常量值等。符号引用属于编译原理的概念,包括以下三类常量:全限定类名和接口名段名和描述符方法名和描述符PSD:\work\WorkSpasce\helloworld\target\classes\jvm\chapter1030>javap-v.\JavaRun.classClassfile/D:/work/WorkSpasce/helloworld/target/classes/jvm/chapter1030/JavaRun.class最后修改时间2022-11-30;大小723字节MD5校验和98ab025cdce5e3f729a05bc7dfcaf720从“JavaRun.java”公共类jvm.chapter1030.JavaRun次要版本:0主要版本:52标志:ACC_PUBLIC、ACC_SUPER常量池:#1=Methodref#8.#26//java/lang/Object."":()V#2=String#27//Windows10#3=Fieldref#7.#28//jvm/chapter1030/JavaRun.SYS_NAME:Ljava/lang/String;#4=Fieldref#29.#30//java/lang/System.out:Ljava/io/PrintStream;#5=String#31//helloworld#6=Methodref#32。#33//java/io/打印tStream.println:(Ljava/lang/String;)V#7=Class#34//jvm/chapter1030/JavaRun#8=Class#35//java/lang/Object#9=Utf8SYS_NAME#10=Utf8Ljava/语言/字符串;#11=Utf8ConstantValue#12=Utf8#13=Utf8()V#14=Utf8Code#15=Utf8LineNumberTable#16=Utf8LocalVariableTable#17=Utf8this#18=Utf8Ljvm/chapter1030/JavaRun;#19=Utf8main#20=Utf8([Ljava/lang/String;)V#21=Utf8args#22=Utf8[Ljava/lang/String;#23=Utf8方法1#24=Utf8源文件#25=Utf8JavaRun.java#26=NameAndType#12:#13//"":()V#27=Utf8Windows10#28=NameAndType#9:#10//SYS_NAME:Ljava/lang/String;#29=Class#36//java/lang/System#30=NameAndType#37:#38//out:Ljava/io/PrintStream;#31=Utf8helloworld#32=Class#39//java/io/PrintStream#33=NameAndType#40:#41//println:(Ljava/lang/String;)V#34=Utf8jvm/chapter1030/JavaRun#35=Utf8java/lang/Object#36=Utf8java/lang/System#37=Utf8out#38=Utf8Ljava/io/PrintStream;#39=Utf8java/io/PrintStream#40=Utf8println#41=Utf8(Ljava/lang/String;)V{publicjvm.chapter1030.JavaRun();descriptor:()Vflags:ACC_PUBLICCode:stack=2,locals=1,args_size=10:aload_01:invokespecial#1//方法java/lang/Object."":()V4:aload_05:ldc#2//字符串Windows107:putfield#3//字段SYS_NAME:Ljava/lang/String;10:returnLineNumberTable:line3:0line5:4LocalVariableTable:StartLengthSlotNameSignature0110thisLjvm/chapter1030/JavaRun;publicstaticvoidmain(java.lang.String[]);描述符:([Ljava/lang/String;)Vflags:ACC_PUBLIC,ACC_STATICCode:stack=2,locals=1,args_size=10:getstatic#4//Fieldjava/lang/System.out:Ljava/io/打印流;3:ldc#5//Stringhelloworld5:invokevirtual#6//方法java/io/PrintStream.println:(Ljava/lang/String;)V8:returnLineNumberTable:line8:0line9:8LocalVariableTable:起始长度槽名签名090args[Ljava/语言/字符串;公共无效方法1();描述符:()Vflags:ACC_PUBLICCode:stack=0,locals=1,args_size=10:returnLineNumberTable:line13:0LocalVariableTable:StartLengthSlotNameSignature010thisLjvm/chapter1030/JavaRun;}SourceFile:“JavaRun.java”