如何降低java GC开销,减少GC次数
其他详见:《如何减少垃圾回收的次数 jvm虚拟机》
1.选择一个较好的GC器
Java9在2017年九月发布,G1(“Garbage First”)垃圾回收器 成为 HotSpot 虚拟机默认的垃圾回收器。从 serial 垃圾回收器到CMS 收集器, JVM 见证了许多 GC 实现,而 G1 将成为其下一代垃圾回收器。
随着垃圾收集器的发展,每一代 GC 与其上一代相比,都带来了巨大的进步和改善。parallel GC 与 serial GC 相比,它让垃圾收集器以多线程的方式工作,充分利用了多核计算机的计算能力。CMS(“Concurrent Mark-Sweep”)收集器与 parallel GC 相比,它将回收过程分成了多个阶段,使得应用线程正在运行的时候,收集工作可以并发地完成,大大改善了频繁执行 “stop-the-world” 的情况。G1 对于拥有大量堆内存的 JVM 表现出更好的性能,并且具有更好的可预测和统一的暂停过程。
2.预测集合的容量,初始化集合时候提供大小
因为java中的集合,底层都使用的是数组(原生数据类型或者基于对象的类型),数组一旦被分配,其大小就不可变,因此添加元素到集合时,大多数情况下都会导致需要重新申请一个新的大容量的数组替换老的数组。
如果没有提供集合的初始化大小,那么大多数集合的实现都尽量优化重新分配数组的处理并且将其开销平摊到最低。不过,在构造集合的时候就提供大小可以得到最佳的效果。
3.直接处理数据流
当处理数据流时,比如从一个文件读取数据或者从网络中下载数据,下面的代码是非常常见的:
byte[] fileData = readFileToByteArray(new File("myfile.txt"));
所产生的字节数组可能被解析 XML 文档、JSON 对象或者协议缓冲消息,以及一些常见的可选项。
当处理大文件或者文件的大小无法预测时,上面的做法很是不明智的,因为当 JVM 无法分配一个缓冲区来处理真正文件时,就会导致OutOfMemeoryErrors。
即使数据的大小是可管理的,当到垃圾回收时,使用上面的模式依然会造成巨大的开销,因为它在堆中分配了一块非常大的区域来存储文件数据。
一种更加好的处理方式是使用合适的 InputStream (比如在这个例子中使用 FileInputStream)直接传递给解析