1.Person(方法区) person(java栈) =new Person()(JAVA堆)
概述:
尽管所有的的方法区逻辑上是属于堆的一部分,但一些简单的实现可能不会选择区进行垃圾收集或者进行压缩;
所以方法区可以看作是一块独立于Java堆的内存空间;
方法区的基本理解:
1.方法区与Java堆一样,是各个线程共享的内存区域;
2.方法区在JVM启动的时候被创建,并且它的实际物理内存和Java堆区一样都可以是不连续的。
3.方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。
4.方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出溢出错误:java.lang.OutOfMemoryError:PerGen space(7之前)或者java.lang.OutOfMemoryError:Metaspace(>=8)
加载第三方jar包过多,大量动态的生成反射类
5.关闭JVM就会释放这个区域的内存;
6.元空间不在虚拟机设置的内存中,而实使用本地内存;
方法区设置大小与OOM
JDK7及以前:
通过-XX:PermSize来设置永久代初始分配空间。默认值是20.75M.
-XX:MaxPerSize来设定永久代最大可分配空间。32位机器默认是64M,64位机器模式是82M
当JVM加载的类信息容量超过了这个值,会报异常OutOfMemoryError:PerGenspace.
JDK8及以后:
1.元数据区大小可以使用参数-XX:MetaspaceSize和-XX:MaxMetaspaceSize指定;
2,默认值依赖平台。windows下,-XX:MetaspaceSize(需要调整)是21M,-XX:MaxMetaspaceSize(不改变)的值是-1,即没有限制。
3.与永久代不同,如果不指定大小,默认情况下,虚拟机会耗尽所有的可用系统内存。
如果元数据区发生溢出,虚拟机一样会抛出OutOfMemoryError.Metaspace.
4.-XX:MetaspaceSize:设置初始的元空间大小。对于一个64的服务器端JVM来说,其默认值的-XX:MetaspaceSize的值位21MB.这就是初始的高水位线,一旦触及,Full GC将会被触发并卸载没用的类。
5.如果初始化高水位线设置过低,上述高水位线调整情况会发生很多次。通过垃圾回收器的日志可以观察到Full GC多次调用。为避免频繁调用GC,建议将-XX:MetaspaceSize=100m设置在一个相对较高的位置;
JDK6方法区内部结构:
类型信息:域信息,方法信息,类信息,接口信息,枚举,注解
运行时常量池:
静态变量:
即时编译器编译的缓存:
方法区的演进:
JDK7:有永久代,但已经逐步“去永久代”,字符串长量池,静态变量保存在堆中;
jdk8之后:无永久代,类型信息,字段,方法,常量保存在本地内存的元空间,但字符串常量池、静态变量仍在堆;
StringTable(字符串常量池)为什么要调整位置:
JDK7中将StringTable放到了堆空间。因为永久代的回收效率很低,在full GC的时候才会触发。而full gc 是老年代的空间不足、永久代不足时才会触发。
这就导致StringTable的回收效率不高。而我们开发中会有大量的字符串被创建,回收效率低。导致永久代内存不足。放到堆里能及时回收内存。
静态变量的存放:
方法区中的垃圾回收:
方法区的垃圾收集主要是两部分:常量池中的废弃的常量和不再使用的类型;