这里将要讲述的是一系列的类似案例,都是在各个产品进行performance tuning时被发现的,非常具有普适性。可以说在日常开发中,有非常大的概率遇到相同或者类似的情形,因此需要对其保持警惕以便避免陷入类似的性能问题。
我们从JAXBContext这个对象开始,JAXBContext 是JAXB API的入口,典型的代码实现如下:
private void unmarshal() {
JAXBContext context = JAXBContext.newInstance(DirectoryConstants.JAXB_CONTEXT_CLASS);
Unmarshaller u = context.createUnmarshaller();
Object obj = u.unmarshal(...);
}
这个是标准使用流程了,首先初始化JAXBContext对象,通过JAXBContext对象创建Unmarshaller对象,然后使用Unmarshaller对象来进行unmarshal操作。
这个写法在功能实现上没有任何问题,但是如果一旦进行压力测试,就会暴露性能问题。JAXBContext对象的初始化是个资源消耗非常大的操作,我们可以通过threaddump进行分析,会发现很多工作线程都在执行JAXBContext.newInstance()这个方法,而不是我们期待的u.unmarshal()。而事实上JAXBContext对象的Sun实现是线程安全的,即容许多线程同时调用一个JAXBContext对象的createUnmarshaller(),因此完全没有必要为每个xml的 marshaling 和 unmarshalling 操作去初始化一次JAXBContext对象。可以参考这里的说明:https://jaxb.dev.java.net/faq/index.html#threadSafety
简单点说,这个一个初始化代价昂贵,却又可重复使用的对象。
因此,我们只需要初始化JAXBContext对象一次并保存起来,然后重复使用这个JAXBContext对象即可。保存JAXBContext对象的方式可以有很多种,比如cache / threadlocal,或者使用一个单例来维持这个对象。比如下面的代码示例:
private void unmarshal() {
JAXBContext context = JAXBContextHolder.get();
...
}
public class JAXBContextHolder {
private static final JAXBContext instance = JAXBContext.newInstance(DirectoryConstants.JAXB_CONTEXT_CLASS);
public static JAXBContext get() {
return instance;
}
}
在实际项目中, 通过上面的简单改进之后,我们当时得到了一个非常巨大的回报:TPS (transactions per second 每秒事务处理量)直接*3 !!
这个案例从技术上讲非常的简单,道理很浅显,相信每个人都能轻松理解。或者说,这是一个“知道了就简单,不知道就容易犯错而不自知”的地方,因此依然有些东西需要注意:
(1) 有哪些对象有类似的特性
目前发现的类似对象有
1. 刚刚上面讲到的JAXB API中的 JAXBContext 对象
2. SOAP API中的javax.xml.soap.SOAPFactory
3. CFX client
通常情况下,在使用各种api或者工具类库时,如果发现调用代码中有类似的初始化语句,都应该稍加注意(除非明确当前代码对性能完全没有要求),可以去查一下这个类对象的javdoc或者直接看源码,如果发现满足上面所说的特性,则应该考虑进行上述的性能优化。
根据经验,类似的初始化对象通常的命名规则都是***Context/***Factory之类,或者***client,遇到类似名字时需要提高警惕。
(2)假设问题已经存在,如果才能在performance tuning中迅速发现问题的代码?
通常的办法就是用thread dump,一般连续dump个3-5次,然后通过分析thread dump信息 (推荐使用eclipse插件 lockness),看当前请求的线程(通常是一个线程池)都在干什么。一般初始化昂贵都昂贵在类似文件IO操作或者加锁之类的地方,很容易在thread dump中被发现。
分享到:
相关推荐
2. **尽量重用对象** - **解释**:频繁创建和销毁对象会消耗大量系统资源,尤其是在Java虚拟机中。使用可变对象如`StringBuilder`来替代不可变对象`String`可以减少对象创建次数。 - **实践**:对于经常变化的数据...
- **数组**:详细阐述了数组的声明、初始化以及访问方式。 - **Java的面向对象特性** - **类与对象**:解释了如何定义类以及如何创建对象,并探讨了类与对象之间的关系。 - **继承**:介绍了一种机制,允许一个...
- 描述了如何初始化安全管理器,并设置必要的安全策略。 2. **Framework的JAAS安全管理** - **基于JAAS的验证**: 利用Java Authentication and Authorization Service(JAAS)提供的API来进行用户的认证和授权。 -...
数据流图(DFD)和数据字典(DD)是结构化分析方法的核心,而继承是面向对象编程中的核心概念,支持代码重用。 软件详细设计涉及图形、表格和语言工具,同时,软件质量保证通过复审、测试和证明来确保。大型软件...
4. **成本效益**:对于企业和个人开发者来说,开源软件降低了初始开发成本,因为无需购买昂贵的商业许可证。 ### 文件结构分析 在提供的压缩包中,`mwsf` 可能是 MWS 框架的主文件或文件夹,包含了框架的核心组件...
15. **使用Lazy实现延迟初始化**:延迟初始化可以避免不必要的资源消耗,直到真正需要时才创建实例。 16. **理解并使用属性(Property)**:属性提供数据封装,同时支持自定义get和set行为,如验证和计算属性。 17...
通过预先初始化一定数量的连接,当应用程序需要时可以从池中获取,使用完毕后归还,而不是直接关闭。这个自定义的MySQL接口类实现了连接池,意味着它能够优化数据库操作的性能,提高系统的响应速度和并发能力。 ...