【问题标题】:Stackoverflow when deserializing synchronizedSet from Hazelcast从 Hazelcast 反序列化 synchronizedSet 时的 Stackoverflow
【发布时间】:2021-03-11 08:51:17
【问题描述】:

考虑以下代码 sn-p 以从 Hazelcast 获取/提交 Collections.synchronizedSet:

IMap imap = getIMapFromHazelcastClient();
Set<UUID> mySet = (Set<UUID>)imap.get("someKey"); //This may trigger a stackOverflow, see below.
if ( mySet == null ){
    mySet = Collections.synchronizedSet(new HashSet<UUID>());
}else{
    mySet = Collections.synchronizedSet(mySet);
}

//Concurrently add/remove elements from mySet

//After all concurrent operations complete, store the updated Set to Hazelcast.
//mySet should contain about 1-1.5K UUIDs at this point, every time.
imap.set("someKey", mySet);

在这段代码运行了几次之后(不知道有多少次,或者为什么),在尝试从 Hazelcast 获取 Set 时触发了以下代码(上面标记):

java.lang.StackOverflowError
at java.base/java.io.ObjectInputStream$PeekInputStream.read(ObjectInputStream.java:2914)
at java.base/java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2930)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUnsignedShort(ObjectInputStream.java:3439)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:3497)
at java.base/java.io.ObjectInputStream.readUTF(ObjectInputStream.java:1242)
at java.base/java.io.ObjectStreamClass.readNonProxy(ObjectStreamClass.java:800)
at java.base/java.io.ObjectInputStream.readClassDescriptor(ObjectInputStream.java:991)
at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2017)
at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1895)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2202)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1712)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:519)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:477)
at java.base/java.util.HashSet.readObject(HashSet.java:344)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor564.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1226)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2401)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2235)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1712)

...About 900 lines of these
at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2540)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2434)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2235)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1712)

at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2540)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2434)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2235)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1712)
at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2540)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2434)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2235)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1712)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:519)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:477)
at com.hazelcast.internal.serialization.impl.JavaDefaultSerializers$JavaSerializer.read(JavaDefaultSerializers.java:84)
at com.hazelcast.internal.serialization.impl.JavaDefaultSerializers$JavaSerializer.read(JavaDefaultSerializers.java:77)
at com.hazelcast.internal.serialization.impl.StreamSerializerAdapter.read(StreamSerializerAdapter.java:48)
at com.hazelcast.internal.serialization.impl.AbstractSerializationService.toObject(AbstractSerializationService.java:187)
at com.hazelcast.client.spi.ClientProxy.toObject(ClientProxy.java:102)
at com.hazelcast.client.proxy.ClientMapProxy.get(ClientMapProxy.java:318)
...

如果相关,应用程序和 Hazelcast (v3.12.9) 在相同的 JVM 版本上运行:OpenJDK 运行时环境(内部版本 15.0.1+9-18)和相同的硬件上。当 Hazelcast 在 v1.8.0 JVM 上运行时观察到相同的行为。

在存储部分用一个简单的 HashSet 替换 synchronizedSet 后,问题似乎解决了:

imap.set("someKey", new HashSet(mySet));

显然,在 Hazelcast 中存储 synchronizedSet 没有任何意义,但是 stackoverflow 是否合理?我错过了什么吗?

【问题讨论】:

    标签: java serialization deserialization stack-overflow hazelcast


    【解决方案1】:

    这不会为我重新创建使用 Hazelcast 4.2-BETA-1 之前的完整代码。这与您的设置有何不同?

        public static void main(String[] args) throws Exception {
            String mapName = "so66579138";
            String key = "k";
    
            Config config = new Config();
            config.getNetworkConfig().getJoin().getAutoDetectionConfig().setEnabled(false);
            config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
    
            HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance(config);
            
            IMap<String, Set<UUID>> imap = hazelcast.getMap(mapName);
            
            Set<UUID> mySet = Collections.synchronizedSet(new HashSet<UUID>());
            for (int i = 0 ; i < 1500 ; i++) {
                mySet.add(UUID.randomUUID());
            }
    
            // PUT
            imap.set(key, mySet);
            
            // GET
            Set<UUID> mySet2 = imap.get(key);
            System.out.println("mySet2.size() == " + mySet2.size());
            System.out.println("mySet2.getClass().getName() == " + mySet2.getClass().getName());
            
            hazelcast.shutdown();
        }
    
    

    【讨论】:

    • 我尝试了一些combo,3.12.9,Java 8,Java 15,上面只是4.2-BETA-1版本
    • 感谢尼尔的回复。不幸的是,我没有重现该问题的特定模式。主要区别在于我的代码可能会在崩溃之前执行多次,而不仅仅是在您的代码中崩溃一次。并且同步集由多个线程更改,并使用从 Hazelcast 接收的 Set 创建(初始化),以防万一。
    • 另外,考虑我的代码是一个由多个线程同时访问的方法(但每个线程的键不同)。
    • 那么在序列化过程中是否可以同时访问同步集?
    • 否,所有对同步集的并发读/写操作在提交到 Hazelcast 之前完成。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多