探索如何以最小的垃圾收集影响和最大的内存利用率创建堆外聚合。
使用Java Map,List和Object创建大型聚合通常会产生大量堆内存开销。 这也意味着,一旦聚合超出范围,垃圾收集器将必须清理这些对象。
阅读这篇简短的文章,了解如何使用Speedment Stream ORM创建堆外聚合,这些聚合可以更有效地利用内存,而对GC的影响很小或没有。
人
假设我们有大量具有以下形状的Person
对象:
public class Person {
private final int age;
private final short height;
private final short weight;
private final String gender;
private final double salary;
…
// Getters and setters hidden for brievity
}
出于争论的目的,我们还可以访问一个名为persons()
的方法,该方法将使用所有这些Person
对象创建一个新的Stream
。
每年龄工资
我们要为每个年龄段创建平均工资。 为了表示汇总的结果,我们将使用称为AgeSalary
的数据类,该数据类将某个年龄与平均工资相关联。
public class AgeSalary {
private int age;
private double avgSalary;
…
// Getters and setters hidden for brievity
}
工资的年龄分组通常需要使用少于100个存储桶,因此此示例仅用于说明原理。 存储桶越多,聚集异常堆的意义就越大。
解
使用Speedment Stream ORM,我们可以通过以下三个步骤得出堆外聚合解决方案:
创建一个聚合器
var aggregator = Aggregator.builderOfType(Person.class, AgeSalary::new)
.on(Person::age).key(AgeSalary::setAge)
.on(Person::salary).average(AgeSalary::setAvgSalary)
.build();
聚合器可以反复使用。
计算聚合
var aggregation = persons().collect(aggregator.createCollector());
使用聚合器,我们创建了一个标准的Java流收集器,其内部状态完全处于堆外。
使用汇总结果
aggregation.streamAndClose()
.forEach(System.out::println);
由于聚合保存的是堆外存储的数据,因此可以从显式关闭中受益,而不仅仅是在很长时间之后才进行清理。 可以通过调用close()
方法(可能是利用AutoCloseable
特性close()
来完成关闭聚合的操作,或者如上例所示,使用streamAndClose()
返回流,该流将在流终止后关闭Aggregation
。
一站式服务
上面的代码可以简化为一种有效的代码:
persons().collect(Aggregator.builderOfType(Person.class, AgeSalary::new)
.on(Person::age).key(AgeSalary::setAge)
.on(Person::salary).average(AgeSalary::setAvgSalary)
.build()
.createCollector()
).streamAndClose()
.forEach(System.out::println);
还支持并行聚合。 只需添加流操作Stream::parallel
并使用ForkJoin
池完成聚合。
资源资源
在此处下载Speedment
在此处阅读有关堆外聚合的更多信息
翻译自: https://www.javacodegeeks.com/2018/12/java-aggregate-data-heap.html