Cache all computed type adapters. On one particularly violent test (issue 375) this improves performance by 77%.

This commit is contained in:
Jesse Wilson 2011-11-26 15:30:38 +00:00
parent ddde79c861
commit 4c06b01369
3 changed files with 8 additions and 126 deletions

View File

@ -114,6 +114,9 @@ public final class Gson {
}
};
private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache
= Collections.synchronizedMap(new HashMap<TypeToken<?>, TypeAdapter<?>>());
private final List<TypeAdapter.Factory> factories;
private final ConstructorConstructor constructorConstructor;
@ -328,7 +331,10 @@ public final class Gson {
* deserialize {@code type}.
*/
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
// TODO: cache?
TypeAdapter<?> cached = typeTokenCache.get(type);
if (cached != null) {
return (TypeAdapter<T>) cached;
}
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
@SuppressWarnings("unchecked") // the key and value type parameters always agree
@ -344,6 +350,7 @@ public final class Gson {
TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) {
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}

View File

@ -1,42 +0,0 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* A cache that evict objects from the cache using an LRU (least recently used)
* policy. Object start getting evicted from the cache once the {@code maxCapacity}
* is reached.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
final class LruCache<K, V> extends LinkedHashMap<K, V> {
private final int maxCapacity;
public LruCache(int maxCapacity) {
super(maxCapacity, 0.7F, true);
this.maxCapacity = maxCapacity;
}
@Override protected boolean removeEldestEntry(Map.Entry<K, V> entry) {
return size() > maxCapacity;
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson;
import junit.framework.TestCase;
/**
* Unit test for the {@link LruCache} class.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
public class LruCacheTest extends TestCase {
public void testCacheHitAndMiss() throws Exception {
LruCache<String, Integer> cache = new LruCache<String, Integer>(3);
String key = "key1";
assertNull(cache.get(key));
cache.put(key, 1);
assertEquals(1, cache.get(key).intValue());
String key2 = "key2";
cache.put(key2, 2);
assertEquals(1, cache.get(key).intValue());
assertEquals(2, cache.get(key2).intValue());
}
public void testCacheKeyOverwrite() throws Exception {
LruCache<String, Integer> cache = new LruCache<String, Integer>(3);
String key = "key1";
assertNull(cache.get(key));
cache.put(key, 1);
assertEquals(1, cache.get(key).intValue());
cache.put(key, 5);
assertEquals(5, cache.get(key).intValue());
}
public void testCacheEviction() throws Exception {
LruCache<String, Integer> cache = new LruCache<String, Integer>(5);
cache.put("key1", 1);
cache.put("key2", 2);
cache.put("key3", 3);
cache.put("key4", 4);
cache.put("key5", 5);
assertEquals(1, cache.get("key1").intValue());
assertEquals(2, cache.get("key2").intValue());
assertEquals(3, cache.get("key3").intValue());
assertEquals(4, cache.get("key4").intValue());
assertEquals(5, cache.get("key5").intValue());
// Access key1 to show key2 will be evicted (shows not a FIFO cache)
cache.get("key1");
cache.get("key3");
cache.put("key6", 6);
cache.put("key7", 7);
assertEquals(1, cache.get("key1").intValue());
assertNull(cache.get("key2"));
assertEquals(3, cache.get("key3").intValue());
assertNull(cache.get("key4"));
assertEquals(5, cache.get("key5").intValue());
assertEquals(6, cache.get("key6").intValue());
assertEquals(7, cache.get("key7").intValue());
}
}