论坛首页 Java企业应用论坛

吹牛:我写的JSONParser可能是这个星球上最快了(Java)

浏览 143467 次
该帖已经被评为精华帖
作者 正文
   发表时间: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,死循环了,不是对内存要求高。

能够把序列化的对象结构提供出来么?



程序的健壮性不是说不支持就好的, 要告诉客户发生了才是关键。


在考虑底成本实现循环引用的检测的办法,可能可行,这两天有空就试一下!
0 请登录后投票
   发表时间: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,死循环了,不是对内存要求高。

能够把序列化的对象结构提供出来么?



程序的健壮性不是说不支持就好的, 要告诉客户发生了才是关键。


在考虑底成本实现循环引用的检测的办法,可能可行,这两天有空就试一下!


这个我早就提出来了,不知道你有没有看到,实现这个功能非常有必要.

0 请登录后投票
   发表时间:2011-01-10  
楼主,能否简单说一下,做了哪些改进
我checkout下代码,看了一下,还是基于反射的,
0 请登录后投票
   发表时间:2011-01-10  
接到通知,公网访问的IP地址变更,新的访问地址如下:

http://119.38.217.15/svn/fastjson/trunk/
0 请登录后投票
   发表时间:2011-01-10  
yefeng 写道
楼主,能否简单说一下,做了哪些改进
我checkout下代码,看了一下,还是基于反射的,


是否使用反射,这不是性能的关键点,使用cglib能够提升一点性能,但是影响不大。

其中很多优化性能的办法,你可以看源代码和之前的一些讨论。
0 请登录后投票
   发表时间:2011-01-10  
wenshao 写道
yefeng 写道
楼主,能否简单说一下,做了哪些改进
我checkout下代码,看了一下,还是基于反射的,


是否使用反射,这不是性能的关键点,使用cglib能够提升一点性能,但是影响不大。

其中很多优化性能的办法,你可以看源代码和之前的一些讨论。

前面30页,实在太长了,能否有个总结性的地方
0 请登录后投票
   发表时间:2011-01-10  
qiangshao说的很对,温少可以先关注一下他的那个问题。。。
0 请登录后投票
   发表时间:2011-01-10  
回luffyke和qiangshao:

我还在做呢,循环检测的实现还没做完,因为今晚处理了些别的事情。

做了一半,检测的实现在这个类JSONSerializerContext中,还没加入进去,得明天晚上再搞了。

今晚优化了String的序列化性能。



0 请登录后投票
   发表时间:2011-01-11  
wenshao 写道
回luffyke和qiangshao:

我还在做呢,循环检测的实现还没做完,因为今晚处理了些别的事情。

做了一半,检测的实现在这个类JSONSerializerContext中,还没加入进去,得明天晚上再搞了。

今晚优化了String的序列化性能。




呵呵,慢慢来,刚才更新了下代码,正在看呢。。。加油咯。。。
0 请登录后投票
   发表时间: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标识忽略的办法来解决循环引用的。

大家给些参考意见。

0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics