使用记事本在使用Streams API时产生垃圾

问题描述 投票:0回答:1

今天,我正在尝试编年史地图。这是一个代码示例:

package experimental;

import net.openhft.chronicle.core.values.IntValue;
import net.openhft.chronicle.map.ChronicleMap;
import net.openhft.chronicle.values.Values;

public class Tmp {

    public static void main(String[] args) {

        try (ChronicleMap<IntValue, User> users = ChronicleMap
                .of(IntValue.class, User.class)
                .name("users")
                .entries(100_000_000)
                .create();) {

            User user = Values.newHeapInstance(User.class);
            IntValue id = Values.newHeapInstance(IntValue.class);

            for (int i = 1; i < 100_000_000; i++) {

                user.setId(i);
                user.setBalance(Math.random() * 1_000_000);

                id.setValue(i);
                users.put(id, user);

                if (i % 100 == 0) {
                    System.out.println(i + ". " +
                            users.values()
                                    .stream()
                                    .max(User::compareTo)
                                    .map(User::getBalance)
                                    .get());
                }
            }
        }
    }

    public interface User extends Comparable<User> {

        int getId();
        void setId(int id);
        double getBalance();
        void setBalance(double age);

        @Override
        default int compareTo(User other) {
            return Double.compare(getBalance(), other.getBalance());
        }
    }
}

如您在上面的代码中看到的,我只是创建User对象并将其放在Chronicle Map中,在第100条记录之后,我仅以最大余额打印User。但不幸的是,它正在产生一些垃圾。当我用VisualVM监视它时,得到以下信息:

VisualVM Screenshot

似乎在Chronicle Map中使用流会产生垃圾。

所以我的问题是:*这是否意味着我不应该将Chronicle Map与Streams API一起使用。*还有其他解决方案/方式吗?*如何以正确的方式过滤/搜索编年史地图,因为我除了只是放入/获取数据。

java stream garbage-collection chronicle chronicle-map
1个回答
0
投票

ChronicleMapentrySet().iterator()(以及keySet()values()上的迭代器)已实现,以便在对其进行迭代之前将编年史地图的segment中的所有对象都转储到内存中。

您可以通过调用map.segments()检查您有多少段。您还可以在ChronicleMap构建阶段配置它,请查看ChronicleMapBuilder javadoc

因此,在迭代过程中,您应该定期将大约numEntries / numSegments个条目定期转储到内存中[[一次,其中numEntries是编年史地图的大小。

您可以通过细分上下文API通过重用对象,在编年史地图上实现流处理,从而避免创建大量垃圾:

User[] maxUser = new User[1]; for (int i = 0; i < users.segments(); i++) { try (MapSegmentContext<IntValue, User, ?> c = map.segmentContext(i)) { c.forEachSegmentEntry((MapEntry<IntValue, User> e) -> { User user = e.value().get(); if (maxUser[0] == null || user.compareTo(maxUser[0]) > 0) { // Note that you cannot just assign `maxUser[0] = user`: // this object will be reused by the SegmentContext later // in the iteration, and it's contents will be rewritten. // Check out the doc for Data.get(). if (maxUser[0] == null) { maxUser[0] = Values.newHeapInstance(User.class); } User newMaxUser = e.value().getUsing(maxUser[0]); // assert the object is indeed reused assert newMaxUser == maxUser[0]; } }); } }

链接到Data.get()的文档。

以上示例的代码改编自Data.get()

© www.soinside.com 2019 - 2024. All rights reserved.