关于java:MySQL查询中超出了GC开销限制

GC overhead limit exceeded in MySQL query

我有一个由170k项组成的大型数据库,每个项目有20-150个功能。 当我运行方法,该方法将这些数据检索到一个由item_id和要素列表组成的地图中时,我得到Exception in thread"main" java.lang.OutOfMemoryError: GC overhead limit exceeded。 该方法运行大约30分钟并抛出异常。 这是方法:

1
2
3
4
5
6
7
8
9
10
11
12
public Map<Integer, List<ItemFeatureMapping>> getItemFeatures() {
    List<Item> allItems = getAllItems();
    Map<Integer, List<ItemFeatureMapping>> result = new HashMap<>();
    for (Item i : allItems) {
        List<ItemFeatureMapping> itemFeatures = new ArrayList<>();
        for (ItemFeatureMapping feature: i.getItemFeatures()) {
            itemFeatures.add(feature);
        }
        result.put(i.getId(), itemFeatures);
    }
    return result;
}

我查看了手册:

The parallel collector will throw an OutOfMemoryError if too much time
is being spent in garbage collection: if more than 98% of the total
time is spent in garbage collection and less than 2% of the heap is
recovered, an OutOfMemoryError will be thrown. This feature is
designed to prevent applications from running for an extended period
of time while making little or no progress because the heap is too
small. If necessary, this feature can be disabled by adding the option
-XX:-UseGCOverheadLimit to the command line.

我该如何解决这个问题? 或者是否可以优化方法?

P.S。:我试图通过命令行,但得到Command not found的错误。 但是,我不喜欢这个解决方案,因为该方法可能会运行很长时间。


将目标地图/列表添加到目标地图/列表后,可以从列表allItemsitem.getItemFeatures()中删除每个已处理项目。然后,此项目使用的内存可以被垃圾收集并由您创建的地图/列表重用。

另外,您可以使用构造函数中的预期大小初始化集合。通过这种方式,您不会为分配中的条目分配但从未使用过的地方浪费任何内存。

如果这不能解决您的问题,则必须增加堆大小。因为否则所有功能的表示将不适合您分配的内存:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public Map<Integer, List<ItemFeatureMapping>> getItemFeatures() {
    List<Item> allItems = getAllItems();
    Map<Integer, List<ItemFeatureMapping>> result = new HashMap<>(allItems.size(), 1f);
    Iterator<Item> iterator = allItems.iterator();
    while (iterator.hasNext()) {
        Item item = iterator.next();
        List<ItemFeatureMapping> itemFeatures = new ArrayList<>(item.getItemFeatures().size());

        Iterator<ItemFeatureMapping> iteratorFeature = item.getItemFeatures().iterator();
        while (iteratorFeature.hasNext()) {
            ItemFeatureMapping feature = iteratorFeature.next();
            itemFeatures.add(feature);
            iterator.remove();
        }
        result.put(item.getId(), itemFeatures);
        iterator.remove();
    }
    return result;
}

您可以在循环外创建一个列表实例,然后使用清除列表来代替为每个循环执行创建新的itemFeatures对象

1
itemFeatures.clear();

并且,正如@dabaicai所提到的,尝试给它更多的jvm堆大小。

另外,为了帮助更快地调试问题,请尝试包含所有可能的信息,例如

  • Java版本
  • 堆大小
  • jvm参数