方法区
- jdk1.7以及之前是用永久代实现的,逻辑上属于堆的一部分,方法区里面存放类的信息、常量、即时编译器编译后的代码缓存等,方法区上限:-XX:MaxPermSize
- jdk1.8之后使用元空间替代,元空间使用本地内存,并且把字符串常量池移到了堆空间里面。元空间上限:-XX:MaxMetaspaceSize, 我们一般会对这个参数产生误解:-XX:metaspaceSize,这个参数并不是元空间的初始大小,当元空间的大小达到一定程度(高水位线)时,此时jvm会进行垃圾回收,因为方法区的垃圾收集条件比较的苛刻,回收的效果也不理想,为了避免短时间内再次触发垃圾回收操作,jvm会根据垃圾回收释放的空间升高或者降低高水位线。当元空间剩余内存的大小/元空间全部内存的大小,这个比值如果超过了 -XX:MaxMetaspaceFreeRatio的值,那么就会降低高水位线,如果比值小于 -XX:MinMetaspaceFreeRatio,就会升高高水位线。-XX:metaspaceSize这个参数规定的就是高水位线的初始值。
回收方法区
方法区的垃圾回收性价比是比较低的,主要回收两部分的内容:
- 常量,回收废弃的常量和对象比较相似,以string常量举例,如果没有任何字符串对象引用字符串常量池的string常量,那么就会被清理出常量池,符号引用也是一样的。
- 类型,类型的回收要满足一下三个条件:
- 类型的实例对象以及全部被回收了
- 加载这个类型的类加载器也以及被回收了
- 类型对应的java.lang.Class对象也没有在任何地方被引用了 在大量使用了反射、动态代理、CGLIB等字节码框架的场景中,通常需要java虚拟机有类型卸载的能力