今天我为大家分享的内容是《利于GC的编码》,内容比较简单,有不合理的地方欢迎指正。
一、利于GC的编码
JVM每个java程序员都认识,这里不做拓展;
二、JVM的特点
JVM具有高效的创建和回收对象的能力,喜好小对象,生命周期短,不改变指向的对象。 对生命周期短的对象,GC回收高效(新生代的复制算法,不需要扫描和复制就能回收)
切勿滥用对象池,否则对象池不一定能提高性能,反倒会影响 GC效率。一般程序猿都有一个误区,总是动不动就使用对象池作为缓冲。
什么时候用对象池?
创建对象的开销较大。
涉及到DB/IO/Network等紧张资源的对象创建。
对象池生命周期长,每次full gc都要处理(mark, compact, etc) , 涉及多线程共享问题,对象池可能带来同步等额外开销
容易产生内存泄漏。
三、hashMap编码
当使用HashMap时,尽量减少resize。 减少resize可以避免没有必要的array copying, gc碎片等问题。一起来看看hashMap源码。
新增元素的源码
达到阀值时进行了resize,HashMap翻倍
扩容后,HashMap会重新将元素按照hash算法插入
在new ArrayList时,尽量估算size,在创建的时候把size确定 ,如果依赖于动态分配,每次分配是最大长度的1.5倍,会造成资源浪费,也会影响GC的效率
对于只需要顺序访问,不需要随机访问的List,用LinkedList代替ArrayList ,因为LinkedList本质是链表;
所以我们尽量预测集合的容量。
四、内存泄漏
java不是有自动回收内存吗?不需要关注内存呀? 错,大错特错。
用通俗的话来描述一下Java的内存泄漏:在有限的空间内,存满了有用和无用的东西,GC无法分清哪些是有用的,哪些是没有用的,无法进行清理。
Java内存泄漏类型 (自己划分,不一定权威)
- 累计:Heap不断变大,直到OOM ;
- 临时:Heap临时/瞬间变得很大,在某个时刻会突然发很小,导致频繁Full GC;
Java内存泄漏的几个经典原因
1. 对象定义在错误的范围
接下来看一个例子
2. 异常(Exception)处理不严谨,导致资源没有释放
例如DB操作时菜鸟经常犯的错误,例子如下
3. 没有控制好集合数据的大小
4. String 的substring导致内存泄漏
1.5的问题,我本地的1.6版本已经不存在该问题,1.7以后肯定是没有问题
错误写法
正确写法
- 减少“+”去拼接String ,尽量使用StringBuilder和StringBuffer;
- GC调优 (不做拓展) – 分配合适的堆大小 – 采用合适的垃圾回收器;
- 良好的编程习惯 – 尽量少用静态对象发量;
- 避免集中创建对象尤其是大对象;
- 不要在经常调用的方法中创建对象;
- 应该定义为局部变量,则不要定义为类的变量 ;
- 预估好数据库中查询出的数据量,数据太多,造成OOM 的异常。
本文档来自支付产品技术交流群的聊天记录整理,由志愿者整理并发布到本网站。如需要及时收到来自支付产品技术交流群的最新消息,请扫码关注“凤凰牌老熊”的微信公众号。 本群面向支付行业的有经验(2年以上)的产品经理、软件工程师、架构师等,提供交流平台。如想加入本群,请在本文评论中留言(不公开),说明所在的公司、负责的工作、入群分享的主题和时间。