元数据区<br>
1.7以前加方法区(或者永久代),1.8以后叫元空间,1.8以后把字符串常量池、静态变量、常量移去了堆里面。原因是以前方法区主要存储的类相关描述信息,不好计算大小,也不好进行垃圾回收,导致内存泄漏,容易出现java.lang.OutOfMemoryError: PermGen
<u><b><font color="#c41230">元空间里面保存的就是类的元数据,如方法、字段、类、包的描述信息</font></b></u>,这些信息可以用于创建文档、跟踪代码中的依赖性、执行编译时检查
类加载器存储的位置就是元空间,每一个类加载器的存储区域都称作一个元空间,所有的元空间合在一起就是我们一直说的元空间。当一个类加载器被垃圾回收器标记为不再存活,其对应的元空间会被回收。
存在的问题:由于元空间的内存分配值组块方式的,所以存在内存碎片问题
<b style=""><font color="#16884a">元空间如何提高性能(面试题)<br>1. 永久代里面的常量池都移到堆里面,只保存元数据,从而让 Full GC 不再关心方法区<br>2. 元空间使用直接内存,理论上系统内存有多大,元空间就可以有多大,理论上不存在 OOM(因为有大小,所以还是存在oom),其实也可以通过:`-XX:MetaspaceSize` 来控制它的初始大小<br>3. 元空间有单独的元空间虚拟机执行内存分配与垃圾回收</font></b>
以后遇到java.lang.OutOfMemoryError: Metaspace 就是元空间的OOM ,一般不会出现,可以通过工具VisualVM监控,因为这里存储的类、方法等描述信息,那么可能是1.Metaspace 设置小了,2.或者一次性加载了太多类,3.java反射的滥用,出现bytecode
面试题:java反射速度慢的原因<br>
一个是Java实现的,另一个是native code实现的。Java实现的版本在初始化时需要较多时间,但长久来说性能较好;native版本正好相反,启动时相对较快,但运行时间长了之后速度就比不过Java版了。这是HotSpot的优化方式带来的性能特性,同时也是许多虚拟机的共同点:跨越native边界会对优化有阻碍作用,它就像个黑箱一样让虚拟机难以分析也将其内联,于是运行时间长了之后反而是托管版本的代码更快些<br><br>为了权衡两个版本的性能,Sun的JDK使用了“inflation”的技巧:让Java方法在被反射调用时,开头若干次使用native版,等反射调用次数超过阈值时则生成一个专用的MethodAccessor实现类,生成其中的invoke()方法的字节码,以后对该Java方法的反射调用就会使用Java版
运行时常量
内容概要:class文件元信息描述,编译后的代码数据,引用类型数据,类文件常量池。<br><br>所谓的运行时常量池其实就是将编译后的类信息放入运行时的一个区域中,用来动态获取类信息。<br><br>运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中,也就是说,每个class都有一个运行时常量池,类在解析之后,将符号引用替换成直接引用,与全局常量池中的引用值保持一致<br>
直接内存<br>
NIO的Buffer提供了一个可以不经过JVM内存直接访问系统物理内存的类——DirectBuffer。 DirectBuffer类继承自ByteBuffer,但和普通的ByteBuffer不同,普通的ByteBuffer仍在JVM堆上分配内存,其最大内存受到最大堆内存的限制;而DirectBuffer直接分配在物理内存中,并不占用堆空间。
就是物理内存,理论上是不会出现内存溢出。但是物理机也有内存限制所以还是会出现内存溢出。