温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

什么是JVM元数据区

发布时间:2021-07-19 09:43:43 来源:亿速云 阅读:286 作者:chen 栏目:大数据

这篇文章主要讲解了“什么是JVM元数据区”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“什么是JVM元数据区”吧!


 
元数据区

元数据区的概念出现在Java8以后,在Java8以前成为方法区,元数据区也是一块线程共享的内存区域,主要用来保存被虚拟机加载的类信息、常量、静态变量以及即时编译器编译后的代码等数据。

由于元数据存储的信息不容易变动,因此它被安置在一块堆外内存,大小由-XX:MaxMetaspaceSize指定。

public class MetaSpaceTest {
   public static void main(String[] args) {        int i = 0;        try {            for (i = 0; i < 100000; i++) {                new CglibBean(new HashMap<>());            }        } catch (Exception e) {            System.out.println(e.getMessage());        } finally {            System.out.println("total create count:" + i);        }    }
   public static class CglibBean {
       public CglibBean(Object object) {            Enhancer enhancer = new Enhancer();            enhancer.setUseCache(false);            enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> obj);            enhancer.setSuperclass(object.getClass());            enhancer.create();        }    }}
 

上述代码通过Cglib生成大量的HashMap代理,下面我们在运行这段代码的时候指定下列参数

-XX:MaxMetaspaceSize=100M -XX:+PrintGCDetails
 
什么是JVM元数据区  


当我们程序循环至3660次,也就是说我们大约在生成了约3660个代理类以后元数据区发生了内存溢出,下面将MaxMetaspaceSize改为50M执行,

什么是JVM元数据区  


从上图可以看出当我们生成了1710个代理类以后元数据区发生了内存溢出,可见一个元数据区的大小决定了Java虚拟机可以装载的类的多少。

 
运行时常量池

在元数据区中还有一块区域称为运行时常量池,此区域用来程序运行期间产生的常量,以及编译期生成的各种字面量和符号引用经类加载后的内容。

在Java中大概存储三种常量池概念,下面我们来讲一下Java中其他两种常量池,帮助读者了解他们中的区别。

首先大家在理解常量池的时候不要简单的理解为被final修饰的变量,常量在这里的含义是一切不变的东西,包括final修饰的变量、字面量、类和接口全限定名、字段、方法名称以及修饰符等永恒不变的东西

 类文件常量池

类文件常量池是指.class文件中的Constant_Pool项,如下图,类文件常量池存放的都是一些字面量和符号引用。什么是JVM元数据区

并不是所有的字面量都会存储在类文件常量池中,比如对于方法内(注意是方法)整数字面量,如果值在-32768~32767之间则会被直接嵌入JVM指令中去,不会保存在常量池中。所以读者不会在常量池中知道CONSTANT_Integer_info为1的符号引用。

类文件常量池产生于编译时期,当JVM加载类文件时会将类文件常量池中的符合引用替换直接引用,加载之后的类文件信息将会被存放在运行时常量池。

 字符串池

字符串池存在JDK1.6以前是存放在永久区中,但是在JDK1.7以后就被转移到堆上。

public static void intern() {    String s1 = new String("he") + new String("llo");    String s2 = s1.intern();    System.out.println(s1 == s2);}
 

上述代码在JDK1.6的时候将会创建6个对象,首先new String("he")会在堆上创一个对象,并且"he"字面量会在永久区的字符串池上创建一个对象,new String("llo")同理创建了两个对象,最后的+又创建了一个对象,当调用intern()方法时,首先会去查找字符串池查找是否有hello内容的对象,发现没有则会在永久区中再创建一个对象,因此总共有6个对象,由于s1是堆中的对象,s2是永久区字符串池中的对象,因此s1==s2结果为false,详情如下图

什么是JVM元数据区  


但是在JDK1.6以后效果不再如此,原因就是由于字符串常量池被移到了堆中,intern方法也做了优化,在JDK1.6以后上述代码将会创建5个对象,首先new String("he")会在堆上创一个对象,并且"he"字面量也会在堆上创建一个对象, new String("llo")同理创建了两个对象,最后的+又创建了一个对象。当intern调用时,首先会在字符串池中查找是否有hello内容的对象,发现没有,此时不会主动创建而是先去查找堆中是否有hello内容的对象,如果有则直接将指针指向堆中的示例,因此这里一共会创建5个对象,由于s1和s2指向的是同一个对象实例,因此s1==s2为true,详情如下图

什么是JVM元数据区  
 

问题

为了帮助各位读者真正理解字符串常量池,下面有两段代码,请在脑海中给出结果,然后再进行Coding验证

public static void intern() {    String s1 = new String("he") + new String("llo");    String s2 = s1.intern();    String s3 = "hello";    System.out.println(s1 == s3);    System.out.println(s1 == s2);}
 
public static void intern() {    String s3 = "hello";    String s1 = new String("he") + new String("llo");    String s2 = s1.intern();    System.out.println(s1 == s3);    System.out.println(s1 == s2);}

感谢各位的阅读,以上就是“什么是JVM元数据区”的内容了,经过本文的学习后,相信大家对什么是JVM元数据区这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

jvm
AI