koupleless / koupleless

modular dev framework and serving platform to enable app evolve from monolithic to microservices and also serverless smoothly. 模块化研发框架与运维调度系统,帮助应用解决研发运维系列痛点问题,省资源、秒级启动、灵活部署、快速需求交付等
https://koupleless.io
Apache License 2.0
164 stars 35 forks source link

Hessian serializer problem leading to Java heap space #81

Closed linwaiwai closed 6 months ago

linwaiwai commented 7 months ago

Describe the question or bug

java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3746) ~[?:?]
    at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:120) ~[?:?]
    at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:95) ~[?:?]
    at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:156) ~[?:?]
    at com.caucho.hessian.io.Hessian2Output.flushBuffer(Hessian2Output.java:1628) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.Hessian2Output.writeByteStream(Hessian2Output.java:1283) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.InputStreamSerializer.writeObject(InputStreamSerializer.java:70) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:465) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer$ObjectFieldSerializer.serialize(UnsafeSerializer.java:299) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer.writeInstance(UnsafeSerializer.java:218) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer.writeObject(UnsafeSerializer.java:172) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:465) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer$ObjectFieldSerializer.serialize(UnsafeSerializer.java:299) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer.writeInstance(UnsafeSerializer.java:218) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer.writeObject(UnsafeSerializer.java:172) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:465) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer$ObjectFieldSerializer.serialize(UnsafeSerializer.java:299) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer.writeInstance(UnsafeSerializer.java:218) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer.writeObject(UnsafeSerializer.java:172) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:465) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer$ObjectFieldSerializer.serialize(UnsafeSerializer.java:299) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer.writeInstance(UnsafeSerializer.java:218) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer.writeObject(UnsafeSerializer.java:172) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:465) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer$ObjectFieldSerializer.serialize(UnsafeSerializer.java:299) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer.writeInstance(UnsafeSerializer.java:218) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer.writeObject(UnsafeSerializer.java:172) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:465) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer$ObjectFieldSerializer.serialize(UnsafeSerializer.java:299) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer.writeInstance(UnsafeSerializer.java:218) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.UnsafeSerializer.writeObject(UnsafeSerializer.java:172) ~[hessian-4.0.66.jar:3.1.0]
    at com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:465) ~[hessian-4.0.66.jar:3.1.0]

Expected behavior

I have a biz function

public Mono<Void> filter(ServerWebExchange exchange, Map<String, Object> config) ;

when master biz invoking the biz function , the problem happens.

Mono, ServerWebExchange, Map in the biz are provided by master biz.

Actual behavior

when I trace the bug, I got:

// SpringServiceInvoker.java
private Object invokeServiceCrossClassLoader(MethodInvocation invocation)
                                                                             throws InvocationTargetException,
                                                                             IllegalAccessException){
....
   Object[] serviceMethodArguments = (Object[]) serializeTransform(clientMethodArguments,
            serviceClassLoader);
   Class[] serviceMethodArgumentTypes = (Class[]) serializeTransform(
            clientMethodArgumentTypes, serviceClassLoader);
....
}
// serializeTransform.java

     public static Object serializeTransform(Object source, ClassLoader targetClassLoader) {
        Object target;
        ClassLoader currentContextClassloader = Thread.currentThread().getContextClassLoader();
        try {
            if (targetClassLoader != null) {
                Thread.currentThread().setContextClassLoader(targetClassLoader);
            }
            SerializerFactory serializerFactory = new SerializerFactory();
            serializerFactory.setAllowNonSerializable(true);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            Hessian2Output h2o = new Hessian2Output(bos);
            h2o.setSerializerFactory(serializerFactory);
            h2o.writeObject(source);
            h2o.flush();
            byte[] content = bos.toByteArray();

            Hessian2Input h2i = new Hessian2Input(new ByteArrayInputStream(content));
            h2i.setSerializerFactory(serializerFactory);
            target = h2i.readObject();
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        } finally {
            Thread.currentThread().setContextClassLoader(currentContextClassloader);
        }
        return target;
    }

Since the source can been array, the lacking of judge source to single or array could be the issue to make "JAVA HEAP" happen.

Steps to reproduce

Screenshots

Minimal yet complete reproducer code (or GitHub URL to code)

Environment

lvjing2 commented 6 months ago

fixed by #87