被static修饰的map、list GC问题

1 篇文章 0 订阅

环境:java1.8   -Xms10m -Xmx10m -XX:+PrintGCDetails

最近在研究GC时,发生一些问题想了好久才想明白,先上测试代码。

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

class OOMData {

    private static ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>();

    private static ArrayList<String> list = new ArrayList<>();

    public void testString() {
        String a = "www.baidu.com";
        while (true) {
            a += (new Random().nextInt(888888888) + new Random().nextInt(999999999)
                    + getRandomString(123) + getRandomString(345)
                    + getRandomString(789) + "哈哈哈哈哈啊哈哈哈哈"
                    + getRandomString(234) );
        }
    }

    public void testStaticMap() {
        int i = 1;
        String a = "test";
        while (true) {
            map.put(i++, getRandomString(1000));
        }
    }

    public void testStaticList() {
        while (true) {
            list.add("test");
        }
    }


    //length用户要求产生字符串的长度
    public static String getRandomString(int length){
        String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random=new Random();
        StringBuffer sb=new StringBuffer();
        for(int i=0;i<length;i++){
            int number=random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }


}



public class OOMTest {

    public static void main(String[] args) {
        OOMData data = new OOMData();
        data.testStaticList();
    }

}

下面上测试结果:

运行testString()方法抛出的异常为:(即测试字符串方法,jdk1.8以后将字符串常量池转移到堆中,每次字符串改变后都会在堆中新建一个字符串对象,直至内存溢出,这个GC日志分析请移步https://blog.csdn.net/weixin_38342534/article/details/102182145

java.lang.OutOfMemoryError: Java heap space


运行testStaticMap()方法后抛出的异常为:

java.lang.OutOfMemoryError: GC overhead limit exceeded

运行testStaticList()方法抛出的异常为:

java.lang.OutOfMemoryError: Java heap space

下面这两个我刚开始不是很理解,因为我都使用了static进行修饰,被static修饰的类会存放在元空间,不会占用堆内存,而元空间的大小理论上跟笔记本的物理内存一样大。且报错并不是java.lang.OutOfMemoryError: Metaspace 一个是java.lang.OutOfMemoryError: GC overhead limit exceeded 即程序用98%的时间回收了不到2%的堆内存。一个是java.lang.OutOfMemoryError: Java heap space即堆old区满了。贴出GC日志

testStaticList

testStaticMap

 

通过GC日志可以看出两个都是因为堆内存被占满导致的OOM,说下原因是因为ArrayList底层是使用的数组,而这个数组是ArrayList定义的成员变量Object[],成员变量是存在堆内存中的,所以才会java heap space。而ConcurrentHashMap底层的链表和红黑树结构也都是在类中定义的成员变量,而每次扩展也都会生成一些新的变量,(底层原理具体请看源码或者别的博客)所以最后young区和old区全部被占满。

这说明,被static修饰的容器容易导致oom不是因为存入了元空间,元空间内存不够导致的,而是因为被static修饰的容器,是GC Roots的对象之一,在它下面进行可达性分析的时候,会一直可达,所以会导致GC的时候,不能被回收,从而导致OOM

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值