JVM(19):StringTable为什么要调整?、静态变量放在哪里?、方法区的垃圾回收、运行时数据区总结

一、StringTable为什么要调整?

        jdk7中将stringTable放到了堆空间中。因为永久代的回收效率很低,在full gc的时候才会触发。而full gc是老年代的空间不足、永久代不足时才会触发。

        这就导致stringTable回收效率不高。而我们开发中会有大量的字符串被创建,回收效率低,导致永久代内存不足。放到堆里,能及时回收内存。

二、静态变量放在哪里?

        staticobj随着Test的类型信息存放在方法区,instanceobj随着Test的对象实例存放在Java堆,localobject则是存放在foo()方法栈帧的局部变量表中。

        测试发现:三个对象的数据在内存中的地址都落在Eden区范围内,所以结论:只要是对象实例必然会在Java堆中分配。 

        接着,找到了一个引用该staticobj对象的地方,是在一个java.lang.class的实例里,并且给出了这个实例的地址,通过Inspector查看该对象实例,可以清楚看到这确实是一个java.lang.class类型的对象实例,里面有一个名为staticobj的实例字段:

        从《Java虚拟机规范》所定义的概念模型来看,所有class相关的信息都应该存放在方法区之中,但方法区该如何实现,《Java虚拟机规范》并未做出规定,这就成了一件允许不同虚拟机自己灵活把握的事情。JDK 7及其以后版本的HotSpot虚拟机选择把静态变量与类型在Java语言一端的映射class对象存放在一起,存储于Java堆之中,从我们的实验中也明确验证了这一点。

三、方法区的垃圾回收

        有些人认为方法区(如Hotspot虚拟机中的元空间或者永久代)是没有垃圾收集行为的,其实不然。《Java虚拟机规范》对方法区的约束是非常宽松的,提到过可以不要求虚拟机在方法区中实现垃圾收集。事实上也确实有未实现或未能完整实现方法区类型卸载的收集器存在(如JDK 11时期的zGC收集器就不支持类卸载)。

        一般来说这个区域的回收效果比较难令人满意,尤其是类型的卸载,条件相当苛刻。但是这部分区域的回收有时又确实是必要的。以前sun公司的Bug列表中,曾出现过的若干个严重的Bug就是由于低版本的HotSpot虚拟机对此区域未完全回收而导致内存泄漏。

        方法区的垃圾收集主要回收两部分内容:常量池中废弃的常量和不再使用的类型。

        先来说说方法区内常量池之中主要存放的两大类常量:字面量和符号引用。字面量比较接近Java语言层次的常量概念,如文本字符串、被声明为final的常量值等。而符号引用则属于编译原理方面的概念,包括下面三类常量:

  1. 类和接口的全限定名
  2. 字段的名称和描述符
  3. 方法的名称和描述符

        HotSpot虚拟机对常量池的回收策略是很明确的,只要常量池中的常量没有被任何地方引用,就可以被回收。回收废弃常量与回收Java堆中的对象非常类似。

        判定一个常量是否“废弃”还是相对简单,而要判定一个类型是否属于“不再被使用的类”的条件就比较苛刻了。需要同时满足下面三个条件:

  • 该类所有的实例都已经被回收,也就是Java堆中不存在该类及其任何派生子类的实例。
  • 加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如OSGi、SP的重加载等,否则通常是很难达成的。
  • 该类对应的java.lang.class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

        Java虚拟机被允许对满足上述三个条件的无用类进行回收,这里说的仅仅是“被允许”,而并不是和对象一样,没有引用了就必然会回收。关于是否要对类型进行回收,HotSpot虚拟机提供了-Xnoclassgc参数进行控制,还可以使用-verbose:class以及-XX:+Traceclass-Loading、-XX:+TraceclassUnLoading查看类加载和卸载信息。

        在大量使用反射、动态代理、cGLib等字节码框架,动态生成JSP以及osGi这类频繁自定义类加载器的场景中,通常都需要Java虚拟机具备类型卸载的能力,以保证不会对方法区造成过大的内存压力。

四、运行时数据区总结

        百度

        三面:说一下JVM内存模型吧,有哪些区?分别干什么的?

        蚂蚁金服:

        Java8的内存分代改进

        JvM内存分哪几个区,每个区的作用是什么?

        一面:JVM内存分布/内存结构?栈和堆的区别?堆的结构?为什么两个survivor区?

        二面: Eden和survior的比例分配

        小米:

        jvm内存分区,为什么要有新生代和老年代

        字节跳动:

        二面:Java的内存分区

        二面:讲讲jvm运行时数据库区什么时候对象会进入老年代?

        京东:

        JVM的内存结构,Eden和Survivor比例。

        VM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和Survivor。

        天猫:

        一面: Jvm内存模型以及分区,需要详细到每个区放什么。

        一面:JVM的内存模型,Java8做了什么修改

        拼多多:

        JVM内存分哪几个区,每个区的作用是什么?

        美团:

        java内存分配

        jvm的永久代中会发生垃圾回收吗?

        一面:jvm内存分区,为什么要有新生代和老年代?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

游王子og

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值