该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2011-01-10
sdh5724 写道 wenshao 写道 lqixv 写道 这个好像对内存要求太高了,我开发用的机器,全部内存才 2G,使用了你的这个 fastjson 后,总是内存溢出,没法跑。
Caused by: java.lang.StackOverflowError at com.alibaba.fastjson.serializer.FieldSerializer.writePrefix(FieldSerializer.java:54) at com.alibaba.fastjson.serializer.StringFieldSerializer.write(StringFieldSerializer.java:29) at com.alibaba.fastjson.serializer.FieldSerializer.write(FieldSerializer.java:64) at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:162) at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:156) at com.alibaba.fastjson.serializer.ObjectFieldSerializer.write(ObjectFieldSerializer.java:47) at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:162) at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:156) at com.alibaba.fastjson.serializer.ListSerializer.write(ListSerializer.java:71) at com.alibaba.fastjson.serializer.ListFieldSerializer.write(ListFieldSerializer.java:31) at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:162) 。。。。。。 这个是BUG,死循环了,不是对内存要求高。 能够把序列化的对象结构提供出来么? 程序的健壮性不是说不支持就好的, 要告诉客户发生了才是关键。 在考虑底成本实现循环引用的检测的办法,可能可行,这两天有空就试一下! |
|
返回顶楼 | |
发表时间:2011-01-10
qiangshao 写道 wenshao 写道 举例:
User user = new User(); List<User> userList = new ArrayList<User>(); String jsonString1 = JSON.toJSONStringEx(user); String jsonString2 = JSON.toJSONStringEx(userList); User user1 = JSON.parseObject(User.class, jsonString1 ); List<User> userList1 = JSON.parseArray(User.class, jsonString2 ); 还有一个比较关心的是 一些字段的过滤 ,比如一个对象循环引用,或者这个对象非常复杂,时间使用时 那些字段根本不需要。 这个功能是非常重要的,对提升性能来说也是一个突破点, 最好能提供模板. wenshao 写道 sdh5724 写道 wenshao 写道 lqixv 写道 这个好像对内存要求太高了,我开发用的机器,全部内存才 2G,使用了你的这个 fastjson 后,总是内存溢出,没法跑。
Caused by: java.lang.StackOverflowError at com.alibaba.fastjson.serializer.FieldSerializer.writePrefix(FieldSerializer.java:54) at com.alibaba.fastjson.serializer.StringFieldSerializer.write(StringFieldSerializer.java:29) at com.alibaba.fastjson.serializer.FieldSerializer.write(FieldSerializer.java:64) at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:162) at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:156) at com.alibaba.fastjson.serializer.ObjectFieldSerializer.write(ObjectFieldSerializer.java:47) at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:162) at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:156) at com.alibaba.fastjson.serializer.ListSerializer.write(ListSerializer.java:71) at com.alibaba.fastjson.serializer.ListFieldSerializer.write(ListFieldSerializer.java:31) at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:162) 。。。。。。 这个是BUG,死循环了,不是对内存要求高。 能够把序列化的对象结构提供出来么? 程序的健壮性不是说不支持就好的, 要告诉客户发生了才是关键。 在考虑底成本实现循环引用的检测的办法,可能可行,这两天有空就试一下! 这个我早就提出来了,不知道你有没有看到,实现这个功能非常有必要. |
|
返回顶楼 | |
发表时间:2011-01-10
楼主,能否简单说一下,做了哪些改进
我checkout下代码,看了一下,还是基于反射的, |
|
返回顶楼 | |
发表时间:2011-01-10
接到通知,公网访问的IP地址变更,新的访问地址如下:
http://119.38.217.15/svn/fastjson/trunk/ |
|
返回顶楼 | |
发表时间:2011-01-10
yefeng 写道 楼主,能否简单说一下,做了哪些改进
我checkout下代码,看了一下,还是基于反射的, 是否使用反射,这不是性能的关键点,使用cglib能够提升一点性能,但是影响不大。 其中很多优化性能的办法,你可以看源代码和之前的一些讨论。 |
|
返回顶楼 | |
发表时间:2011-01-10
wenshao 写道 yefeng 写道 楼主,能否简单说一下,做了哪些改进
我checkout下代码,看了一下,还是基于反射的, 是否使用反射,这不是性能的关键点,使用cglib能够提升一点性能,但是影响不大。 其中很多优化性能的办法,你可以看源代码和之前的一些讨论。 前面30页,实在太长了,能否有个总结性的地方 |
|
返回顶楼 | |
发表时间:2011-01-10
qiangshao说的很对,温少可以先关注一下他的那个问题。。。
|
|
返回顶楼 | |
发表时间:2011-01-10
回luffyke和qiangshao:
我还在做呢,循环检测的实现还没做完,因为今晚处理了些别的事情。 做了一半,检测的实现在这个类JSONSerializerContext中,还没加入进去,得明天晚上再搞了。 今晚优化了String的序列化性能。 |
|
返回顶楼 | |
发表时间:2011-01-11
wenshao 写道 回luffyke和qiangshao:
我还在做呢,循环检测的实现还没做完,因为今晚处理了些别的事情。 做了一半,检测的实现在这个类JSONSerializerContext中,还没加入进去,得明天晚上再搞了。 今晚优化了String的序列化性能。 呵呵,慢慢来,刚才更新了下代码,正在看呢。。。加油咯。。。 |
|
返回顶楼 | |
发表时间:2011-01-11
最后修改:2011-01-11
半夜睡不着 ...
想了一些处理循环引用的办法,其中一个超级简单。 第一种,流氓粗暴的办法: try { // ... } catch (StackOverflowError e) { throw new JSONException("maybe circular references", e); } 很流氓,但是很简单很有效,不会影响效率。 第二种,编写存放引用的类,如果发现引用重复,则做处理。这个类如下: public final class JSONSerializerContext { public static final int DEFAULT_TABLE_SIZE = 64; private final Entry[] buckets; private final int indexMask; public JSONSerializerContext() { this(DEFAULT_TABLE_SIZE); } public JSONSerializerContext(int tableSize) { this.indexMask = tableSize - 1; this.buckets = new Entry[tableSize]; } // 添加引用,如果存在则返回true,否则返回false public final boolean put(Object obj) { final int hash = System.identityHashCode(obj); final int bucket = hash & indexMask; for (Entry entry = buckets[bucket]; entry != null; entry = entry.next) { if (obj == entry.object) { return true; } } Entry entry = new Entry(obj, hash, buckets[bucket]); buckets[bucket] = entry; return false; } protected static final class Entry { public final int hashCode; public final Object object; public Entry next; public Entry(Object object, int hash, Entry next) { this.object = object; this.next = next; this.hashCode = hash; } } } 只需要JavaBean的序列化是调用put方法检测就可以了,应该对性能影响不大,具体数据等有空测试才能具体确定影响多大,但初步估计性能影响较小。 对于出现循环引用的情况,处理办法两种:抛异常或者忽略。如果是抛异常,还不如上面第一种方式有效,如果忽略,还不如这样写: import com.alibaba.fastjson.annotation.JSONField; public class Category { private Category parent; private List<Category> children = new ArrayList<Category>(); @JSONField(serialize=false) // 标识不需要序列化 public Category getParent() { return parent; } public void setParent(Category parent) { this.parent = parent; } public List<Category> getChildren() { return children; } public void setChildren(List<Category> children) { this.children = children; } } 我在网上搜索了一下,JSON.NET也是采用Annotation标识忽略的办法来解决循环引用的。 大家给些参考意见。 |
|
返回顶楼 | |