在以前的学习中,咱们在Gson全解析(上)Gson使用的基础到分别运用了JsonSerializer
和JsonDeserializer
进行JSON和java实体类之间的相互转化。java
在Gson全解析(中)中使用了TypeAdapter
中的read和write方法分别进行了反序列化和序列化。
咱们曾讲到使用TypeAdapter
会比使用JsonSerializer
和JsonDeserializer
更加的高效,原理是怎么样的呢?性能提高明显吗?git
下面的文章给你答案。github
如下Gson性能分析,内容整理自: GSON TYPEADAPTER EXAMPLE SERIALISE LARGE OBJECTSjson
采用YourKit 做为性能分析工具。数组
首先来看看咱们提供一个大一点的数据来论证下面一些方法的优缺点。 这里提供类LargeData.java
,并分为四个部分进行内存消耗的分析:ide
public class LargeData { private long[] numbers; public void create(final int length) { numbers = new long[length]; for (int i = 0; i < length; i++) { numbers[i] = i; } } public long[] getNumbers() { return numbers; } }
看看下面的JsonSerializer
:工具
package com.javacreed.examples.gson.part1; import java.lang.reflect.Type; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; public class LargeDataSerialiser implements JsonSerializer<LargeData> { @Override public JsonElement serialize(final LargeData data, final Type typeOfSrc, final JsonSerializationContext context) { final JsonArray jsonNumbers = new JsonArray(); for (final long number : data.getNumbers()) { jsonNumbers.add(new JsonPrimitive(number)); } final JsonObject jsonObject = new JsonObject(); jsonObject.add("numbers", jsonNumbers); return jsonObject; } }
上面的代码实现了从java对象>转化>JSON数组的序列化过程。下面的代码实现了配置和初始化的过程,被写入文件。这里能够看到的是对LargeData
初始化了10485760
个元素:源码分析
package com.javacreed.examples.gson.part1; import java.io.File; import java.io.IOException; import java.io.PrintStream; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class Main { public static void main(final String[] args) throws IOException { // Configure GSON final GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(LargeData.class, new LargeDataSerialiser()); gsonBuilder.setPrettyPrinting(); final Gson gson = gsonBuilder.create(); final LargeData data = new LargeData(); data.create(10485760); final String json = gson.toJson(data); final File dir = new File("target/part1"); dir.mkdirs(); try (PrintStream out = new PrintStream(new File(dir, "output.json"), "UTF-8")) { out.println(json); } System.out.println("Done"); } }
这个例子实现了建立java对象而且转化为JSON字符串并写入文件的整个过程。下面的图标展现了内存的消耗状况:性能
上面的的LargeData在这里会消耗89MB的内存,从java对象转化为JSON字符串的过程将会消耗大概16s的时间而且须要超过1GB的内存。也就是说,序列化1MB的数据咱们须要大约11MB的工做空间。1:11的确实是一个不小的比列。下面的 图片会展现整个过程的几个阶段。学习
能够看到的是,这里有四个方块分别表明不一样的阶段,(可是IO 缓冲区并无在这里获得使用,因此以灰色进行标注。)整个过程从java对象(蓝色方块),而后由LargeDataSerialiser
类建立的JSONElement对象(红色方块),而后这些临时的对象又被转化为JSON 字符串(绿色方块),上面的示例代码使用PrintStream
将内容输出到文件中并无使用任何缓冲区。
完成了第1部分的分析,接下来下面的分析流程是同样的:
以前的系列文章中都对Gson基础的使用进行了很好的讲解,能够回顾一下。
TypeAdapter
相比 于上面的方法,并无使用JSONElement对象,而是直接将Java对象啊转化为了JSON对象。
package com.javacreed.examples.gson.part2; import java.io.IOException; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; public class LargeDataTypeAdapter extends TypeAdapter<LargeData> { @Override public LargeData read(final JsonReader in) throws IOException { throw new UnsupportedOperationException("Coming soon"); } @Override public void write(final JsonWriter out, final LargeData data) throws IOException { out.beginObject(); out.name("numbers"); out.beginArray(); for (final long number : data.getNumbers()) { out.value(number); } out.endArray(); out.endObject(); } }
一样会须要配置,这里主要使用的方法是gsonBuilder.registerTypeAdapter(LargeData.class, new LargeDataTypeAdapter());
:
package com.javacreed.examples.gson.part2; import java.io.File; import java.io.IOException; import java.io.PrintStream; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class Main { public static void main(final String[] args) throws IOException { // Configure GSON final GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(LargeData.class, new LargeDataTypeAdapter()); gsonBuilder.setPrettyPrinting(); final Gson gson = gsonBuilder.create(); final LargeData data = new LargeData(); data.create(10485760); final String json = gson.toJson(data); final File dir = new File("target/part2"); dir.mkdirs(); try (PrintStream out = new PrintStream(new File(dir, "output.json"), "UTF-8")) { out.println(json); } System.out.println("Done"); } }
上面的代码完成的是从java对象 >转化>JSON 字符串并最终写入文件的过程。看看下面的性能分析图表:
和最初的那个方法同样,这里的LargeData对象将会须要89MB的内存,从java对象转化为JSON字符串的过程须要消耗4s的时间,大概650MB的内存。也就是说,序列化1MB的数据,大概须要7.5MB的内存空间。相比于以前的第一种JsonSerializer方法,这里减小了接近一半的内存消耗。一样的,来看看这个方法的几个过程:
这里的序列化过程主要有两个阶段,相比于以前的JSONSerializer
的序列化过程,这里没有了转化为JSONElement的过程,也就完成了内存消耗的减小。
下面的代码,咱们使用上面一样的TypeAdapter,只不过咱们直接在main()方法中修改Gson的用法,以流的形式进行输出。
package com.javacreed.examples.gson.part3; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class Main { public static void main(final String[] args) throws IOException { // Configure GSON final GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(LargeData.class, new LargeDataTypeAdapter()); gsonBuilder.setPrettyPrinting(); final Gson gson = gsonBuilder.create(); final LargeData data = new LargeData(); data.create(10485760); final File dir = new File("target/part3"); dir.mkdirs(); try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(dir, "output.json")), "UTF-8"))) { gson.toJson(data, out); } System.out.println("Done"); } }
这个例子一样是将java对象转化为JSON字符串而且输出,也来看看下面的性能分析图表:
能够看到的是一样的最初产生的数据是89MB,序列化过程将java对象转化为JSON字符串花了大概三秒钟的时间,消耗大概160MB的内存。也就是说序列化1MB的数据咱们须要大概2MB的内存空间。相比于以前的两种方法,有了很大的改进。
这个方法一样的是使用了两个阶段。不过在上面一个示例中的绿色方块部分在这里没有使用,这里直接完成了java对象到IO 缓冲区的转化并写入文件。
虽然这里并非Gson的关系,可是咱们使用Gson的方法极大的减小了内存消耗,因此说在使用开源库的时候,可以正确高效的使用API也显得尤其重要。
一样的使用第一个例子中的JsonSerializer,这里的配置须要注意的是gsonBuilder.registerTypeAdapter(LargeData.class, new LargeDataSerialiser());
package com.javacreed.examples.gson.part4; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class Main { public static void main(final String[] args) throws IOException { // Configure GSON final GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(LargeData.class, new LargeDataSerialiser()); gsonBuilder.setPrettyPrinting(); final Gson gson = gsonBuilder.create(); final LargeData data = new LargeData(); data.create(10485760); final File dir = new File("target/part4"); dir.mkdirs(); try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(dir, "output.json")), "UTF-8"))) { gson.toJson(data, out); } System.out.println("Done"); } }
通过前面的分析,咱们这里也能够这道这里主要分为三个阶段,下面提供性能分析图和JSONSerializer的阶段流程图:
这里能够看到三个阶段完成的工做消耗了11s的时间,730MB的内存空间。也就是说1:8的比例。能够相比上面的例子,知道这里使用JSONSerializer产生了JSONElement对象消耗了不少的内存。
在上面的分析过程当中,咱们采用了GSON的两种不一样的方然完成了序列化一个大数据的过程,而且比较了不一样的方法之间的差别。上面的第三种方法(TypeAdapter的流式处理)被论证为最合适的,消耗最少内存的一种方法。
Gson主要分红两部分,一个就是数据拆解,一个是数据封装。
https://sites.google.com/site/gson/gson-user-guide
翻译原文,根据原文作出了较大改动。
1 SIMPLE GSON EXAMPLE
2 GSON DESERIALISER EXAMPLE
3 GSON ANNOTATIONS EXAMPLE
4 GSON SERIALISER EXAMPLE
5 GSON TYPEADAPTER EXAMPLE
6 GSON TYPEADAPTER EXAMPLE SERIALISE LARGE OBJECTS
另附: 你真的会用Gson吗?Gson使用指南(一)系列文章
本篇文章是本系列博客的第三篇文章。将从源码角度以及Gson的深刻用法讲起,一块儿来学习吧。
本系列文章是基于Gson官方使用指导(Gson User Guide)以及Gson解析的优秀外文(来自http://www.javacreed.com/ )作出的一个翻译和概括。
博客原连接:
Gson全解析(上)-Gson基础
Gson全解析(中)-TypeAdapter的使用
Gson全解析(下)-Gson性能分析
from: http://www.jianshu.com/p/8cc857583ff4