为什么Java 8取消了永久代?

  • Post category:Java

为什么Java 8取消了永久代?

在Java 8之前,Java 虚拟机中存在永久代(PermGen)来存储类、方法等元数据信息。 但是,由于永久代的机制设计存在一些问题,在JDK 8中已经被移除,用元空间(Metaspace)取代。

永久代的问题:

  1. 永久代只有限定大小,当应用程序动态加载大量类和方法时,会频繁触发Full GC,影响系统的性能。

  2. 由于永久代的最大值是有限定的,在类加载达到限制之后会出现OOM错误。

metaspace的优点:

  1. 由于metaspace内存使用直接从未使用过的内存中分配,并且不需要Full GC,在内存占用较大时,用户可以使用后备内存作为备选方案。

  2. 使用元空间的另一个优点是支持压缩,当未使用的类类型被卸载时,反应到VM中,VM会自动收缩的空间,这样就能够避免发生内存溢出的情况。

示例说明:

  1. 一个简单的示例,通过产生大量的字符串对象来模拟永久代内存溢出。
import java.util.ArrayList;
import java.util.List;

public class PermGenOutOfMemory {
   public static void main(String[] args) {
       try {
           List<String> l = new ArrayList<String>();      
           for (int i = 0; i < Integer.MAX_VALUE; i++) {
               String t = String.valueOf(i).intern();
               l.add(t);
           }
       } catch (Exception e) {
           e.printStackTrace();
       } catch (Throwable e) {
           e.printStackTrace();
       }
   }
}

执行此示例后,JVM会抛出OutOfMemoryError:PermGen space异常。我们无法通过指定JVM的启动参数来解决这个问题。

  1. 在JDK 8中,上述问题已被解决。
import java.util.ArrayList;
import java.util.List;

public class PermGenOutOfMemory {
   public static void main(String[] args) {
       try {
           List<String> l = new ArrayList<String>();      
           for (int i = 0; i < Integer.MAX_VALUE; i++) {
               String t = String.valueOf(i).intern();
               l.add(t);
           }
       } catch (Exception e) {
           e.printStackTrace();
       } catch (Throwable e) {
           e.printStackTrace();
       }
   }
}

在这个示例中,程序仍然在同样的条件下运行,但是由于JDK 8的元空间的存在,程序不会崩溃。该程序将继续正常运行,直到计算机内存耗尽或启动繁忙。

总结:

永久代的存在与其机制设计所带来的问题是JDK 8放弃使用它的原因。替代的元空间不仅具有动态内存占用,而且还支持压缩。因此,在开发项目和应用程序的过程中,应该始终使用JDK 8或高版本。