美文网首页java
Java代码层优化GC

Java代码层优化GC

作者: 扎瓦叔叔 | 来源:发表于2019-05-30 12:05 被阅读0次

    也是最近,很多服务遇到了gc问题,影响服务的可用性,虽然知道大致的减少对象的创建等,但没有一个较为系统的认知,这里就稍微整理下,辅助以后自己代码的性能(逼格)。

    String对象

    最容易想到的就是减少String对象的创建,因为String对象为final类型,在项目里,可能会出现String+String的操作。在这里,会先生成一个StringBuilder对象,最后StringBuilder.toString()再生成一个String对象,所以这种a+b的操作会额外生成两个对象。但是JVM对+法的重载用StringBuilder来实现了,所以仅当出现A = a+b;B = A+c的形式出现,

    String result = "a" + "b";
    result += "c";
    System.out.println(result);
    

    当然这种代码如果放在循环中,就会有不可控多个对象的生成。
    可以这样写:

    StringBuilder result = new StringBuilder("a");
    result.append("b").append("c");
    System.out.println(result);
    

    当然不在循环里也可以这样

    String result = a + b + c;
    System.out.println(result);
    

    尽量给数组一个初始容量

    ArrayList和其他一些集合类,底层都是使用Object[]数组实现,当一个数据初始化的时候,系统是不知道你需要多少长度,所以会有一个默认值,当数组长度不足时,它就会被一个全新的,长度更长的数据代替,之前的就会被垃圾回收。所以如果在循环中,这里就会有多次的新数组的分配和更多的旧数组需要被回收
    ~# 多次扩容,多次拷贝
    ~# 内存碎片
    所以在初始化的时候,尽量给数组一个初始值,或者估算一个值

    拆装箱

    在使用List、Map、Set之类的集合类的时候,编译器是通过自动拆装箱来实现的,把原始数据类型装箱到一个对应的对象中,这个对象是可被回收的。也就是每次集合类的一次add操作,都可能会额外分配一个对象来存储原始类型。

    解决方法:有兴趣的同学可以去了解下Trove
    · 提供开放选址的map集合类,效率更高,结构更小
    · 不需要自动装箱操作,直接保存基础类型数据

    循环中集合的返回

    当方法返回一个集合类,通常会填充到一个大的集合对象中,过程中每次方法调用返回会产生大量的临时集合

    List<Item> items = new ArrayList<Item>();
    for (FileData fileData : fileDatas)
    {
    // 每一次调用都会创建一个存储内部临时数组的临时的列表
        items.addAll(readFileItem(fileData));
    }
    

    解决方法:

    List<Item> items = new ArrayList<Item>(fileDatas.size() * avgFileDataSize * 1.5);
    for (FileData fileData : fileDatas)
    {
        readFileItem(fileData, items); // 在内部添加记录
    }
    

    这样可以节省N个List的临时对象

    对象作用域

    尽可能缩小对象的作用域,生命周期
    如果可以在方法内声明的局部变量,就不要声明为实例变量
    static变量尽量用在单例或者不变的对象上

    Immutable Objects

    当Old对象对Young对象引用或者释放的时候,会把Young对象标记为Dirty,不可变对象明显可以较少扫描时候的消耗。同时,也减少了生产环境中一些可变对象可能会引发的bug

    参考

    http://www.importnew.com/10472.html

    相关文章

      网友评论

        本文标题:Java代码层优化GC

        本文链接:https://www.haomeiwen.com/subject/bakcbqtx.html