10

JVM实战04(方法区内存溢出)

 4 years ago
source link: https://lizb0907.github.io/2021/02/22/Jvm-Battle04/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
JVM实战04(方法区内存溢出) — java游戏服务端~我的学习之路

JVM实战04(方法区内存溢出)

目录

JDK8和之后的版本,持久代取消变为元空间,
元空间是本地内存。

2.方法区

1.线程共享,存储虚拟机加载的类型信息、常量、静态变量等。

2.jdk8开始方法区成为一个逻辑上的概念,如上图:
  静态变量和字符串常量池存放在堆中,
  而运行时常量池以及一些类信息存放在元空间。

  方法区由堆和元空间一起组成。
public static void main(String[] args)
{
    Set<String> set = new HashSet<>();
    int i = 0;
    while (true)
    {
        //intern():
        // 1.是一个本地方法
        // 2.如果字符串常量池里面已经包含了等于字符串X的字符串,
        //   那么就返回常量池这个字符串的引用。
        //   如果常量池中不存在,则会把当前字符串添加到常量池,
        //   并返回引用。
        set.add(String.valueOf(i++).intern());
    }

}

设置永久代参数: -XX:PermSize=6m -XX:MaxPermSize=6m

jDK 6:
  报永久代溢出(java.lang.OutOfMemoryError:PermGen space)

jDK 7+:
  7以后的版本,不报错,原因是把字符串常量放到了堆,设置-Xmx堆大小参数才会
  报堆内存溢出。
public class OOMTest
{
    private int[] arr = new int[200];

    private String name = "zhangShan";

    public static void main(String[] args)
    {
        List<Object> list = new ArrayList<>();
        while (true)
        {
            list.add(new OOMTest());
        }
    }
}


JDK1.8:
  1.设置元空间的初始大小和最大大小:-XX:MetaspaceSize=1m -XX:MaxMetaspaceSize=1m
  2.运行时报:
           OutOfMemoryError: Metaspace    //元空间溢出

    原因是因为:
      a.我们结合上面方法区的图可以看到,方法区是一个逻辑上的概念,它横跨堆和元空间。
        我们看到类信息是放到方法区的并且实际属于元空间内存。所以,我们不停的new OOMTest类,
        是添加到元空间的。
      b.本来元空间是本地内存,只要本地内存够大是不会报元空间内存溢出。但是由于我们参数设置了元空间
      最大为1m,所以运行实例代码很快就会报元空间内存溢出。

方法区溢出的场景

1.常量池里对象太大。

2.加载的类的“种类”太多(因为类是存放方法区 ps:实际是元空间那部分):
    .动态代理的操作库生产了大量的动态类
    .JSP项目,JSP太多,因为JSP是第一次被访问的时候才会编译成java类。极端
     情况下,编译项目时没有问题,但请求JSP页面导致类加载过多造成方法区溢出。
    .脚本语言动态加载

避免方法区溢出

1.根据JDK版本,为常量池保留足够空间(主要是字符串常量池):
  JDK 6:     设置合理的永久代参数 -XX:PermSize -XX:MaxPermSize。
  >=JDK 7:   设置合理的堆内存大小Xms、Xmx。

2.防止类加载过多(JD8类信息存放到了元空间):
  <=JDK 7:     设置合理的永久代参数。
  >=JDK 8:     不配置元空间相关配置(JVM动态分配),或配置合理大小的元空间。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK