Java垃圾回收优化策略

时间:2019-03-17 17:22:22

标签: java garbage-collection heap-memory tail-recursion ergonomics

我有一个处理大量数据的Java应用程序。

占用所有内存的方法如下:

这是一个尾部递归方法(我使用蹦床使栈安全),该方法首先通过LinkedList(可以包含很多对象,最多几百万个对象)进行迭代,对于每个对象,我经历另一个int = 1到13的循环。

private TailCall<LinkedList<HandInstance>> 
setDealerHandsInstanceList(LinkedList<HandInstance> handInstanceList,
        LinkedList<HandInstance> dealerHandInstanceList) {

    final LinkedList<HandInstance> handInstanceListP = new LinkedList<>();

    for (HandInstance handInstance : handInstanceList) {

        Shoe shoe = handInstance.getShoe();
        BigDecimal kansAlGespeeldeKaarten = handInstance.getKansAlGespeeldeKaarten();
        int spelerTotaalInitiaal = handInstance.getSpelerTotaalInitiaal();

        for (Kaart kaart : shoe.getDefaultHand()) {
        //(--> defaultHand contains 13 elements)

在defaultHand循环中,我创建了一个新的handInstanceP,对初始handInstance的属性进行了深度复制,并将它们设置为新的handInstanceP。 (同时根据defaultHand-loop更改这些属性。 根据一些if测试,我将此handInstanceP添加到新的LinkedList handInstanceListP或DealerHandInstanceList

在handInstanceList循环的结尾,我执行以下操作:

if (!handInstanceListP.isEmpty()) {
    return call(() -> setDealerHandsInstanceList(handInstanceListP, 
    dealerHandInstanceList));
} else {
    Thread.dumpStack();
    return TailCalls.done(dealerHandInstanceList);
}

我已经尝试研究GC并调整其设置。但是我做的似乎无效。

执行主程序时,出现OutOfMemoryErrors:“ java堆空间”(当我将堆大小增加到总计2gb时)和“超出了GC开销限制”(当我未进行任何设置时,因此使用默认值)尺寸和设置)。 我在Windows 10上运行,带有8GB DDR4内存RAM(请注意,启动程序时我通常只有4-5GB的可用空间)

问题: 使用哪种更合适的GC?并行GC,G1,串行GC,UseConcMarkSweepGC?

我特别需要寻找哪些GC设置?我猜有很多对象只能分配给Young Generation(请参阅在handInstanceList-loop-statement之后声明的对象)。 (例如,我有大约700.000 int被创建) 其他对象是更永久的,例如LinkedLists,但主要是linkedList中的对象。这些被创建最多(大约800万次,并且在苛刻的运行中更多)。我猜这些应该分配给老一代吗?还是可以将它们保留在Young Generation中并增加Young Gen堆大小?

编辑1:我已更改为ArrayLists。

编辑2:确实,这不是垃圾回收的真正问题,更多的是尝试在我的程序中延迟处理此列表。该列表仅出于计算原因而存在,就像您在循环结束时看到的那样,我检查一个空列表,因此以后不需要该列表。我只需要它来更改一个特定的对象,但是它需要很多小的更改,并且每个循环都定义一个小的更改。

如果我使用流,则有两个问题。 如果我有以下内容:

ArrayList<Class> list = new ArrayList<>();
Stream stream = list.stream()
stream.forEach(class ->
{
   Class class2 = new Class(); 
   class2.add(class);
   // other things done with class2
});

如果仅使用并且仅存在于forEach-stream中,则该Class class2对象是否在我的程序中被延迟处理?

另一种可能性:

ArrayList<Class> list = new ArrayList<>();
Class class2 = new Class();
Stream stream = list.stream()
stream.forEach(class ->
{
   class2.add(class);
});

这有可能吗?它看起来像一个愚蠢的问题,但是我真的不习惯流媒体,我不知道有什么可能,什么没有。但是,如果没有最后一个例子,这似乎很奇怪。

0 个答案:

没有答案