2012-11-01 7 views
7

私のタイプミスマッチの問題を解決するには Deserializersを作成し、ObjectMapperに追加しました。しかし、これにより性能が著しく低下します。カスタムデシリアライザでデシリアライズすると、多くのGC呼び出しが発生し、時間がかかります

デフォルトのデシリアライザでは、logcatで1-2ガベージコレクションコールが発生し、カスタムデシリアライザでは少なくとも7-8 GCコールがあるため、処理時間も大幅に増加します。

マイデシリアライザ:

public class Deserializer<T> { 

public JsonDeserializer<T> getDeserializer(final Class<T> cls) { 
    return new JsonDeserializer<T>(){ 

    @Override 
    public T deserialize(JsonParser jp, DeserializationContext arg1) throws IOException, JsonProcessingException { 
     JsonNode node = jp.readValueAsTree(); 
     if (node.isObject()) { 
      return new ObjectMapper().convertValue(node, cls); 
     } 
     return null; 
    } 
}; 
} 
} 

そして、私は

public class DeserializerAttachedMapper<T> { 

    public ObjectMapper getMapperAttachedWith(final Class<T> cls , JsonDeserializer<T> deserializer) { 
     ObjectMapper mapper = new ObjectMapper(); 
     SimpleModule module = new SimpleModule(deserializer.toString(), new Version(1, 0, 0, null, null, null)); 
     module.addDeserializer(cls, deserializer); 
     mapper.registerModule(module); 
     return mapper; 
    } 
} 

EDITマッパーに追加するためにこれを使用しています:が追加されました余分なデータ

私のJSONはかなりの大きさが、巨大ではないのです: 貼り付け済みit here

は今、私はこのコードを使用する場合、同じJSONを解析するために:

String response = ConnectionManager.doGet(mAuthType, url, authToken); 
    FLog.d("location object response" + response); 
    //  SimpleModule module = new SimpleModule("UserModule", new Version(1, 0, 0, null, null, null)); 
    //  JsonDeserializer<User> userDeserializer = new Deserializer<User>().getDeserializer(User.class);  
    //  module.addDeserializer(User.class, userDeserializer); 

    ObjectMapper mapper = new ObjectMapper(); 
    //  mapper.registerModule(module); 
    JsonNode tree = mapper.readTree(response); 
    Integer code = Integer.parseInt(tree.get("code").asText().trim()); 

    if(Constants.API_RESPONSE_SUCCESS_CODE == code) { 
     ExploreLocationObject locationObject = mapper.convertValue(tree.path("response").get("locationObject"), ExploreLocationObject.class); 
     FLog.d("locationObject" + locationObject); 
     FLog.d("locationObject events" + locationObject.getEvents().size()); 
     return locationObject; 
    }  
    return null;  

はその後、私のlogcatはlike this

である。しかし、私は同じJSONのためにこのコードを使用している場合

 String response = ConnectionManager.doGet(mAuthType, url, authToken); 
    FLog.d("location object response" + response); 
    SimpleModule module = new SimpleModule("UserModule", new Version(1, 0, 0, null, null, null)); 
    JsonDeserializer<User> userDeserializer = new Deserializer<User>().getDeserializer(User.class); 

    module.addDeserializer(User.class, userDeserializer); 
    ObjectMapper mapper = new ObjectMapper(); 
    mapper.registerModule(module); 
    JsonNode tree = mapper.readTree(response); 
    Integer code = Integer.parseInt(tree.get("code").asText().trim()); 

    if(Constants.API_RESPONSE_SUCCESS_CODE == code) { 
     ExploreLocationObject locationObject = mapper.convertValue(tree.path("response").get("locationObject"), ExploreLocationObject.class); 
     FLog.d("locationObject" + locationObject); 
     FLog.d("locationObject events" + locationObject.getEvents().size()); 
     return locationObject; 
    }  
    return null;   

はその後、私のlogcatですlike this

+0

1件の追加コメント:あなたが行われる必要があり、次のコードで あなたは再利用し、絶対に確認してください 'ObjectMapper' - それは重いオブジェクトで、リクエストごとに一度に作成するべきではありません。さもなければ、それは間違いなく多くのGC活動を引き起こす可能性がある。上記のコードだけでは分かりません。 – StaxMan

+0

実際、あなたのデシリアライザがObjectMapperを作成していることに気付きました。これは非常にコストがかかります。 'JsonParser 'を使うことでそれを避けることができます。getCodec() 'を呼び出し、結果をObjectMapper(安全なアップキャスト)にキャストします。それもかなり助けになるはずです。 – StaxMan

+0

自分のコードを修正してオブジェクトマッパーをシングルトンに追加したところ、デフォルトのデシリアライザのパフォーマンスは向上しましたが、カスタムデシリアライザの問題はまだ残っています。また、同じモジュールに2つのデシリアライザを追加すると、デフォルトのデシリアライザがカスタムのデシリアライザと呼ばれることに気付きました。 'JsonParser.getCodec()'は静的メソッドではないので、リクエストごとに 'JsonParser'を作成する必要があります。それはあまりにも高価ではないでしょうか? – vKashyap

答えて

2

オブジェクトの大きさはどれくらいですか?コードは基本的にツリーモデル(ドームツリーの一種)を構築し、元のドキュメントと同じくらい3倍から5倍のメモリを使います。だから私はあなたの入力は巨大なJSONドキュメントだと思います。

Streaming APIを使用すると、より効率的なバージョンを作成できます。何かのように:

JsonParser jp = mapper.getJsonFactory().createJsonParser(input); 
JsonToken t = jp.nextToken(); 
if (t == JsonToken.START_OBJECT) { 
    return mapper.readValue(jp, classToBindTo); 
} 
return null; 

あなたが「デフォルト」デシリアライザに委任したいという理由だけで、データバインディング(JsonDeserializerなど)でこれを実装することも可能であるが、それは少し複雑になります。 BeanDeserializerModifierを実装し、 "modifyDeserializer"が呼び出されたときに標準のデシリアライザを置き換える必要があります。中間ツリーモデルを使用する代わりに独自のコードでオリジナルのデシリアライザへの参照を保持し、委譲することができます。

+0

質問を編集し、JSON、解析コード、ログを追加しました。お返事ありがとう – vKashyap

0

ジャクソンに縛られていない場合は、Genson http://code.google.com/p/genson/もお試しください。 あなたのケースでは、2つの主な利点があります:パフォーマンスが緩んでいないので、実装が簡単になります。プロパティイベントが上の文字で始まらない場合は、@JsonProperty( "Event")で注釈を付けます(上の文字から始まる他のプロパティについても同様です)。

Genson genson = new Genson.Builder() 
      .withDeserializerFactory(new EventDeserializerFactory()).create(); 

YourRootClass[] bean = genson.deserialize(json, YourRootClass[].class); 

class EventDeserializerFactory implements Factory<Deserializer<Event>> { 

    public Deserializer<Event> create(Type type, Genson genson) { 
     return new EventDeserializer(genson.getBeanDescriptorFactory().provide(Event.class, 
       genson)); 
    } 

} 

class EventDeserializer implements Deserializer<Event> { 
    private final Deserializer<Event> standardEventDeserializer; 

    public EventDeserializer(Deserializer<Event> standardEventDeserializer) { 
     this.standardEventDeserializer = standardEventDeserializer; 
    } 

    public Event deserialize(ObjectReader reader, Context ctx) throws TransformationException, 
      IOException { 
     if (ValueType.ARRAY == reader.getValueType()) { 
      reader.beginArray().endArray(); 
      return null; 
     } 
     return standardEventDeserializer.deserialize(reader, ctx); 
    } 
} 
+0

ありがとうございます。間違いなくそれを撃つだろう。しかし、私はまずジャクソンでパフォーマンスを改善しようとします。 – vKashyap

関連する問題