项目上线了一个活动,性能压测中某个接口表现不理想。我们是在预发机器压测,预发机器条件不好,不过也不至于压出大量的Error,平均响应时间超过9s。
走读代码,并未发现任何问题。该接口用到内存作为缓存。scheduler定时刷新缓存,不存在缓存击穿的情况。那问题出在哪里?一次一次的请求,响应都是非常快。监控显示压测的gc非常频繁,一分钟甚至上百次的ygc。是什么导致这么频繁的gc呢?代码里并未申请堆空间,因为返回的都是事先刷到内存的一个全局对象,不存在申请对象的情况。
我们压测过程中dump一份内存现场下来,用mat分析发现有很多比较大char[],打开看到char[]的内容就是返回的数据。为什么会有这些char[]?接口return的对象是一个全局对象,不应该有这么多char[]才对。进一步追踪发现这些char[]是com.alibaba.fastjson.serializer.SerializeWriter的buf变量
public final class SerializeWriter extends Writer {
private final static ThreadLocal<char[]> bufLocal = new ThreadLocal<char[]>();
private final static ThreadLocal<byte[]> bytesBufLocal = new ThreadLocal<byte[]>();
private static int BUFFER_THRESHOLD = 1024 * 128;
....
protected char buf[];
....
}
至此问题大致清楚,因为我们返回的对象比较大,在用fastjson往外写的时候,fastjson转换成自己的buf[]。虽然我们每次返回的同一个全局对象,不涉及申请内存。但是fastjison写response流的时候会申请空间,而且空间比实际的对象还要大。解决方法无他就是压缩返回对象。

修改之后压测表现明显改善:
修改前压测数据

修改后压测数据

在项目上线活动中,性能压测揭示了FastJSON在处理大对象时的性能问题。通过MAT分析,发现频繁的GC源于SerializeWriter的buf[]变量。通过对返回对象进行压缩,显著提升了接口响应速度。
3423

被折叠的 条评论
为什么被折叠?



