脑大大开,Java优化有方法

原创
2021/11/02 07:51
阅读数 282

我的Java性能优化实战电子书更新了,新整理了目录,经增加了新的内容,有兴趣的可以试读 https://www.kancloud.cn/xiandafu/javamicrotuning 或者推荐给你朋友。书里介绍了许多有趣的Java知识和性能技巧

如下是新增的节选

4.22 辨别重量级对象

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

public class ObjectMapper extends ObjectCodec implements Versioned, Serializable {
    private static final long serialVersionUID = 2L;
    private static final JavaType JSON_NODE_TYPE = SimpleType.constructUnsafe(JsonNode.class);
    protected static final AnnotationIntrospector DEFAULT_ANNOTATION_INTROSPECTOR = new JacksonAnnotationIntrospector();
    protected static final BaseSettings DEFAULT_BASE;
    protected final JsonFactory _jsonFactory;
    protected TypeFactory _typeFactory;
    protected InjectableValues _injectableValues;
    protected SubtypeResolver _subtypeResolver;
    protected final ConfigOverrides _configOverrides;
    protected SimpleMixInResolver _mixIns;
    protected SerializationConfig _serializationConfig;
    protected DefaultSerializerProvider _serializerProvider;
    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);
        //忽略其他
       
  }

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

再以作者的Beetl模板引擎为例子,可以看到GroupTempalte也是一个重量级对象

public class GroupTemplate {

	/* 模板在运行过程中,class方法,accessory调用等需要的classLoader */
	ClassLoader classLoader = Thread.currentThread().getContextClassLoader() != null
			? Thread.currentThread().getContextClassLoader()
			: GroupTemplate.class.getClassLoader();


	AABuilder attributeAccessFactory = new AABuilder();
	ResourceLoader resourceLoader = null;
	Configuration conf = null;
	TemplateEngine engine = null;
	Cache programCache = ProgramCacheFactory.defaulCache();
	List<Listener> ls = new ArrayList<Listener>();
	// 所有注册的方法
	Map<String, Function> fnMap = new HashMap<String, Function>();
	// 格式化函数
	Map<String, Format> formatMap = new HashMap<String, Format>();
	Map<Class, Format> defaultFormatMap = new HashMap<Class, Format>(0);
	// 虚拟函数
	List<VirtualAttributeEval> virtualAttributeList = new ArrayList<VirtualAttributeEval>();
	Map<Class, VirtualClassAttribute> virtualClass = new HashMap<Class, VirtualClassAttribute>();
	// 标签函数
	Map<String, TagFactory> tagFactoryMap = new HashMap<String, TagFactory>();
	ClassSearch classSearch = null;
	// java调用安全管理器
	NativeSecurityManager nativeSecurity = null;
	ErrorHandler errorHandler = null;
	Map<String, Object> sharedVars = null;

	ContextLocalBuffers buffers = null;
}

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

如下是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
展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部