栈、堆、方法区。关系方法区在哪里?https://docs.oracle.com/javas...《Java虚拟机规范》明确指出:“虽然所有方法区在逻辑上都是堆的一部分,但一些简单的实现可能不会选择执行垃圾收集或压缩。”但是对于HotSpotJVM来说,方法区还有一个别名叫Non-Heap(非堆),目的是和堆区分开来。因此,方法区被看成是独立于Java堆的内存空间。方法区的理解从线程共享与否的角度来看,方法区(MethodArea)和Java堆一样,是各个线程共享的一块内存区域。方法区是在JVM启动时创建的,它的实际物理内存空间可以像Java堆区一样是不连续的。方法区的大小和堆空间一样,可以是固定的,也可以是可扩展的。方法区的大小决定了系统可以保存多少类。如果系统定义的类过多,方法区溢出,虚拟机也会抛出内存溢出错误:java.lang.OutOfMemoryError:PermGenspaceorjava.lang。OutOfMemoryError:Metaspace加载了大量第三方jar包;Tomcat部署的项目太多(30-50);大量动态生成的反射类会在JVM关闭时释放这块区域的内存。HotSpot中方法区的演变是在jdk7之前,习惯上称方法区为永久代。从jdk8开始,永久代被元空间取代。本质上,方法区和永久代是不等价的。仅适用于热点。《Java虚拟机规范》对于方法区如何实现,并没有统一的要求。例如:永久代的概念在BEAJRockit/IBMJ9中是不存在的。现在来看,当年用永久代也不是什么好主意。因此,Java程序更容易出现OOM(超过-XX:MaxPermSize的上限)。在JDK8中,永久代的概念终于被彻底抛弃,取而代之的是像JRockit、J9一样在本地内存中实现的元空间(Metaspace)。本质类似于永久代,是JVM规范中方法区的实现。但是,元空间与永久代最大的区别在于,元空间不在虚拟机设置的内存中,而是使用本地内存。永久代和元空间不仅在名称上发生了变化,而且内部结构也进行了调整。按照《Java虚拟机规范》的规定,如果方法区不能满足新的内存分配要求,就会抛出OOM异常。设置方法区的参数设置方法区的内存大小方法区的大小不一定是固定的,jvm可以根据应用的需要动态调整。jdk7及之前:通过-XX:PermSize设置永久代的初始分配空间。默认值为20.75M-XX:MaxPermSize设置永久代的最大可分配空间。32位机器默认为64M,64位机器模式为82M。当JVM加载的class信息容量超过这个值时,会报OutOfMemoryError:PermGenspace异常。jdk8及以后:元数据区域的大小可以用参数-XX:MetaspaceSize和-XX:MaxMetaspaceSize来指定,取代了上面原来的两个参数。默认值取决于平台。windows下-XX:MetaspaceSize为21M,-XX:MaxMetaspaceSize的值为-1,即没有限制。与永久代不同,如果不指定大小,虚拟机将默认用完所有可用的系统内存。如果元数据区溢出,虚拟机也会抛出异常OutOfMemoryError:Metaspace-XX:MetaspaceSize:Settheinitialmetaspacesize。对于64位服务器端JVM,默认的-XX:MetaspaceSize值为21MB。这是初始的高水位线,一旦达到这个水位线,就会触发FullGC,卸载无用的类(也就是这些类对应的类加载器已经不存在),然后重置高水位线.新高水位线的值取决于GC之后释放了多少元空间。如果释放的空间不够,在不超过MaxMetaspaceSize的情况下适当增加该值。如果需要释放的空间过多,则适当减小该值。如果初始高水位线设置得太低,上述高水位线调整可能会发生多次。通过垃圾收集器的日志可以观察到多次调用FullGC。为了避免频繁的GC,建议将-XX:MetaspaceSize设置为一个比较大的值。方法区存储了什么?《深入理解Java 虚拟机》书上是这样描述MethodArea的存储内容的:用来存储类型信息,常量,静态变量,just-in-time编译器编译后的代码缓存等已经被virtual加载的机器。永久代和Metaspace1.首先要明确:只有HotSpot有永久代。对于BEAJRockit、IBMJ9等,没有永久代的概念。原则上,方法区如何实现属于虚拟机的实现细节,不受《Java虚拟机规范》控制,不要求统一。HotSpotjdk1.6及之前永久代的变化:有永久代(permanentgeneration)jdk1.7:有永久代,但已经逐渐“从永久代中移除”。字符串常量池和静态变量被移除并存储在堆中jdk1.8及以后:没有永久代。类型信息、字段、方法和常量存储在本地内存的元空间中,但字符串常量池仍在堆方法区中。会发生GC吗?有人认为方法区(如HotSpot虚拟机中的元空间或永久代)没有垃圾回收行为,其实不然。《Java虚拟机规范》对方法区的约束非常松散。提到了可能不需要虚拟机在方法区实现垃圾回收。事实上,确实有收集器没有实现或者没有完全实现方法区的类型卸载(比如JDK11时期的ZGC收集器不支持类卸载)。总的来说,该地区的回收效果比较难以令人满意,尤其是卸货类型,条件相当苛刻。但这部分地区的恢复有时是必要的。在之前的Sunbug列表中,出现了几个严重的bug,都是因为低版本的HotSpot虚拟机没有完全回收这块区域,导致内存泄露。方法区垃圾回收主要回收两部分:常量池中过时的常量和不再使用的类型。连续三个码字好不容易求点赞收藏~
