Skip to content

性能优化-重量级对象

About 581 wordsAbout 2 min

性能新书

2026-08-21

5.1 重量级对象

重量级对象是那些构造需要较多初始化过程,或者使用过程中会做缓存的对象。比如,看Jackson的ObjectMapper类定义

public class ObjectMapper extends ObjectCodec implements Versioned, Serializable {
    //忽略其他代码
    protected SerializerFactory _serializerFactory;
    protected DeserializationConfig _deserializationConfig;
    protected DefaultDeserializationContext _deserializationContext;
    protected Set<Object _registeredModuleTypes;
    protected final ConcurrentHashMap<JavaType, JsonDeserializer<Object _rootDeserializers;

如上类有较多需要初始化变量,尤其是集合类型。如果你看初始化构造函数,就能看出来,尤其是_rootDeserializers变量,初始化代码是

 protected ObjectMapper(ObjectMapper src) {
        this._rootDeserializers = new ConcurrentHashMap(64, 0.6F, 2);//忽略其他}

这些集合类通常用来作为缓冲,缓存预处理或者预编译的对象,以提高性能。 如果每次使用时候,都构建ObjectMapper将导致这些优化战术失效

幸运的是,Jackson在官网文档已经说明到整个系统通常只需要一个ObjectMapper实例就可以了。

在代码中,如果把重量级对象当成轻量级对象使用,在方法中调用一次就构造一次,那么性能会急剧下降,一方面,构造这些重量级对象需要较多初始化过程,另外最重要的影响是,重量级对象会通常在反复使用中会缓存一些中间计算过程,ObjectMapper会缓存JsonDeserializer到 _rootDeserializers中,重量级对象通常包含Map,Set,ThreadLocal这些成员变量, 或者包含IO链接。 调用一次的时候就构造一次会导致应用性能急剧减低

如下是ObjectMapper每次使用时候的性能

@BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 5)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Threads(1)
@Fork(1)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
public class HeavyweightObjectTest {/*重用*/
        ObjectMapper objectMapper = new ObjectMapper();
        Data data = null;
        @Benchmark
        public Data createNew() throws IOException {/*每次都构造*/
                ObjectMapper encodeMapper = new ObjectMapper();
                String json = encodeMapper.writeValueAsString(data);
                ObjectMapper decodeMapper = new ObjectMapper();
                Data myData = decodeMapper.readValue(json,Data.class);return myData;
        }
        @Benchmark
        public Data reused() throws IOException {
                String json = objectMapper.writeValueAsString(data);
                Data myData = objectMapper.readValue(json,Data.class);return myData;
        }
        @Setup
        public void init(){
                data = new Data();
                data.setAge(18);
                data.setId(123);
                data.setName("lijiazhi");}
        public static void main(String[] args) throws RunnerException {
                Options opt = new OptionsBuilder().include(HeavyweightObjectTest.class.getSimpleName()).forks(1).build();new Runner(opt).run();}}

测试结果,重用重量级对象性能优势非常明显

Benchmark                                   Mode  Samples     Score  Score error   Units
c.i.c.c.HeavyweightObjectTest.createNew    thrpt        5    38.334        2.962  ops/ms
c.i.c.c.HeavyweightObjectTest.reused       thrpt        5  2316.950       23.807  ops/ms

知行合一