jvm之PermGen的离开与MetaSpace新生

先从代码来看,永生代的更迭

测试代码如下:
    public static void main(String[] args){

        // jdk 1.6 设置 -XX:PermSize=10M -XX:MaxPermSize=10M
        // jdk 1.7 1.8只有设置-Xmx20m -Xms20m -XX:-UseGCOverheadLimit才能起作用(这里的-XX:-UseGCOverheadLimit是关闭GC占用时间过长时会报的异常)
        List<String> list = new ArrayList<String>();
        int i=0;
        while(true){
            list.add(String.valueOf(i++).intern());
        }
    }
  • jdk1.6测试:
    设置-XX:PermSize=10M -XX:MaxPermSize=10M,执行代码,报错:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
	at java.lang.String.intern(Native Method)
	at com.yanming.lession2.main(lession2.java:21)

可以得出结论,在1.6时代,字符串常量存放在永生代中

  • jdk1.7 1.8 测试,继续设置-XX:PermSize=10M -XX:MaxPermSize=10M
    可以发现一只可以运行下去。
    此时,加入设置-Xmx20m -Xms20m
    运行结果:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.lang.Integer.toString(Integer.java:401)
	at java.lang.String.valueOf(String.java:3099)
	at com.yanming.lession2.main(lession2.java:21)
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=10M; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10M; support was removed in 8.0
  • 从结果看到,增加的常量都放到了堆中,所以限制堆内存以后,不断增加常量,堆内存会溢出。并且出现警告,PermSize和MaxPermSize从8中移除
  • 官网有说明
    Area: HotSpot
    Synopsis: In JDK 7, interned strings are no longer allocated in the permanent generation of the Java heap, but are instead allocated in the main part of the Java heap (known as the young and old generations), along with the other objects created by the application. This change will result in more data residing in the main Java heap, and less data in the permanent generation, and thus may require heap sizes to be adjusted. Most applications will see only relatively small differences in heap usage due to this change, but larger applications that load many classes or make heavy use of the String.intern() method will see more significant differences.
    RFE: 6962931

Metaspace
  • 移除永久代(PermGen)的工作从JDK1.7就开始了。

  • JDK1.7中,存储在永久代的部分数据就已经转移到了Java Heap或者是 Native Heap。但永久代仍存在于JDK1.7中,并没完全移除,譬如符号引用(Symbols)转移到了native heap;字面量(interned strings)转移到了java heap;类的静态变量(class statics,Class对象、静态变量)转移到了java heap。

  • 1.8之后彻底移除永久代,取而代之的是元空间Metaspace(即本地内存,独立于jvm之外),不再占用堆内存 ,它可以通过自动增长来避免JDK7以及前期版本中常见的永久内存错误(java.lang.OutOfMemoryError: PermGen),当然JDK8也提供了一个新的设置Matespace内存
    大小的参数,通过这个参数可以设置Matespace内存大小,这样我们可以根据自己
    项目的实际情况,避免过度浪费本地内存,达到有效利用。

  • Metaspace用于存放类元数据,并不是存放常量静态变量等,常量跟1.7一样放入堆中

  • 元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小。

  • 默认情况下,类元数据只受可用的本地内存限制(容量取决于是32位或是64位操作系统的可用虚拟内存大小)

  • 当类元数据区使用量到达MetaspaceSize的时候,会触发垃圾回收,然后回收掉无用的类加载器和class对象

  • -XX:MaxMetaspaceSize=128m,-XX:MaxMetaspaceSize,最大空间,默认是没有限制的.设置最大的元内存空间128m。如果你设置的元内存空间过小,你的应用程序可能得到下面错误:java.lang.OutOfMemoryError: Metadata space

  • -XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。

  • -XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集

  • -XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

更新原因:
  • 字符串放在永久代中(jvm描述方法区是堆的一个逻辑部分),容易出现性能问题和内存溢出。
  • 类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。
  • 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低
  • Oracle 可能会将HotSpot 与 JRockit 合二为一
    参考:
    http://www.cnblogs.com/paddix/p/5309550.html
    https://www.jianshu.com/p/4b4cecc8e262
    https://blog.csdn.net/zhyhang/article/details/17246223/
    https://www.jianshu.com/p/4bcb69fbb1fe
    https://blog.csdn.net/lz710117239/article/details/78838087
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

EmineWang

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

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

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

打赏作者

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

抵扣说明:

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

余额充值