提交 0dc4584e 编写于 作者: D dholmes

8005232: (JEP-149) Class Instance size reduction

Summary: Moved the fields for cached reflection objects into a seperate ReflectionData object to reduce dynamic footprint.
Reviewed-by: dholmes, mchung, shade
Contributed-by: NPeter Levart <peter.levart@gmail.com>
上级 fb749d93
/* /*
* Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -2214,39 +2214,89 @@ public final ...@@ -2214,39 +2214,89 @@ public final
// Caches for certain reflective results // Caches for certain reflective results
private static boolean useCaches = true; private static boolean useCaches = true;
private volatile transient SoftReference<Field[]> declaredFields;
private volatile transient SoftReference<Field[]> publicFields; // reflection data that might get invalidated when JVM TI RedefineClasses() is called
private volatile transient SoftReference<Method[]> declaredMethods; static class ReflectionData<T> {
private volatile transient SoftReference<Method[]> publicMethods; volatile Field[] declaredFields;
private volatile transient SoftReference<Constructor<T>[]> declaredConstructors; volatile Field[] publicFields;
private volatile transient SoftReference<Constructor<T>[]> publicConstructors; volatile Method[] declaredMethods;
// Intermediate results for getFields and getMethods volatile Method[] publicMethods;
private volatile transient SoftReference<Field[]> declaredPublicFields; volatile Constructor<T>[] declaredConstructors;
private volatile transient SoftReference<Method[]> declaredPublicMethods; volatile Constructor<T>[] publicConstructors;
// Intermediate results for getFields and getMethods
volatile Field[] declaredPublicFields;
volatile Method[] declaredPublicMethods;
// Value of classRedefinedCount when we created this ReflectionData instance
final int redefinedCount;
ReflectionData(int redefinedCount) {
this.redefinedCount = redefinedCount;
}
// initialize Unsafe machinery here, since we need to call Class.class instance method
// and have to avoid calling it in the static initializer of the Class class...
private static final Unsafe unsafe;
// offset of Class.reflectionData instance field
private static final long reflectionDataOffset;
static {
unsafe = Unsafe.getUnsafe();
// bypass caches
Field reflectionDataField = searchFields(Class.class.getDeclaredFields0(false),
"reflectionData");
if (reflectionDataField == null) {
throw new Error("No reflectionData field found in java.lang.Class");
}
reflectionDataOffset = unsafe.objectFieldOffset(reflectionDataField);
}
static <T> boolean compareAndSwap(Class<?> clazz,
SoftReference<ReflectionData<T>> oldData,
SoftReference<ReflectionData<T>> newData) {
return unsafe.compareAndSwapObject(clazz, reflectionDataOffset, oldData, newData);
}
}
private volatile transient SoftReference<ReflectionData<T>> reflectionData;
// Incremented by the VM on each call to JVM TI RedefineClasses() // Incremented by the VM on each call to JVM TI RedefineClasses()
// that redefines this class or a superclass. // that redefines this class or a superclass.
private volatile transient int classRedefinedCount = 0; private volatile transient int classRedefinedCount = 0;
// Value of classRedefinedCount when we last cleared the cached values // Lazily create and cache ReflectionData
// that are sensitive to class redefinition. private ReflectionData<T> reflectionData() {
private volatile transient int lastRedefinedCount = 0; SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;
int classRedefinedCount = this.classRedefinedCount;
// Clears cached values that might possibly have been obsoleted by ReflectionData<T> rd;
// a class redefinition. if (useCaches &&
private void clearCachesOnClassRedefinition() { reflectionData != null &&
if (lastRedefinedCount != classRedefinedCount) { (rd = reflectionData.get()) != null &&
declaredFields = publicFields = declaredPublicFields = null; rd.redefinedCount == classRedefinedCount) {
declaredMethods = publicMethods = declaredPublicMethods = null; return rd;
declaredConstructors = publicConstructors = null; }
annotations = declaredAnnotations = null; // else no SoftReference or cleared SoftReference or stale ReflectionData
// -> create and replace new instance
// Use of "volatile" (and synchronization by caller in the case return newReflectionData(reflectionData, classRedefinedCount);
// of annotations) ensures that no thread sees the update to }
// lastRedefinedCount before seeing the caches cleared.
// We do not guard against brief windows during which multiple private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData,
// threads might redundantly work to fill an empty cache. int classRedefinedCount) {
lastRedefinedCount = classRedefinedCount; if (!useCaches) return null;
while (true) {
ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
// try to CAS it...
if (ReflectionData.compareAndSwap(this, oldReflectionData, new SoftReference<>(rd))) {
return rd;
}
// else retry
oldReflectionData = this.reflectionData;
classRedefinedCount = this.classRedefinedCount;
if (oldReflectionData != null &&
(rd = oldReflectionData.get()) != null &&
rd.redefinedCount == classRedefinedCount) {
return rd;
}
} }
} }
...@@ -2289,27 +2339,19 @@ public final ...@@ -2289,27 +2339,19 @@ public final
// via ReflectionFactory.copyField. // via ReflectionFactory.copyField.
private Field[] privateGetDeclaredFields(boolean publicOnly) { private Field[] privateGetDeclaredFields(boolean publicOnly) {
checkInitted(); checkInitted();
Field[] res = null; Field[] res;
if (useCaches) { ReflectionData<T> rd = reflectionData();
clearCachesOnClassRedefinition(); if (rd != null) {
if (publicOnly) { res = publicOnly ? rd.declaredPublicFields : rd.declaredFields;
if (declaredPublicFields != null) {
res = declaredPublicFields.get();
}
} else {
if (declaredFields != null) {
res = declaredFields.get();
}
}
if (res != null) return res; if (res != null) return res;
} }
// No cached value available; request value from VM // No cached value available; request value from VM
res = Reflection.filterFields(this, getDeclaredFields0(publicOnly)); res = Reflection.filterFields(this, getDeclaredFields0(publicOnly));
if (useCaches) { if (rd != null) {
if (publicOnly) { if (publicOnly) {
declaredPublicFields = new SoftReference<>(res); rd.declaredPublicFields = res;
} else { } else {
declaredFields = new SoftReference<>(res); rd.declaredFields = res;
} }
} }
return res; return res;
...@@ -2320,12 +2362,10 @@ public final ...@@ -2320,12 +2362,10 @@ public final
// via ReflectionFactory.copyField. // via ReflectionFactory.copyField.
private Field[] privateGetPublicFields(Set<Class<?>> traversedInterfaces) { private Field[] privateGetPublicFields(Set<Class<?>> traversedInterfaces) {
checkInitted(); checkInitted();
Field[] res = null; Field[] res;
if (useCaches) { ReflectionData<T> rd = reflectionData();
clearCachesOnClassRedefinition(); if (rd != null) {
if (publicFields != null) { res = rd.publicFields;
res = publicFields.get();
}
if (res != null) return res; if (res != null) return res;
} }
...@@ -2358,8 +2398,8 @@ public final ...@@ -2358,8 +2398,8 @@ public final
res = new Field[fields.size()]; res = new Field[fields.size()];
fields.toArray(res); fields.toArray(res);
if (useCaches) { if (rd != null) {
publicFields = new SoftReference<>(res); rd.publicFields = res;
} }
return res; return res;
} }
...@@ -2382,18 +2422,10 @@ public final ...@@ -2382,18 +2422,10 @@ public final
// instead be copied via ReflectionFactory.copyConstructor. // instead be copied via ReflectionFactory.copyConstructor.
private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) { private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) {
checkInitted(); checkInitted();
Constructor<T>[] res = null; Constructor<T>[] res;
if (useCaches) { ReflectionData<T> rd = reflectionData();
clearCachesOnClassRedefinition(); if (rd != null) {
if (publicOnly) { res = publicOnly ? rd.publicConstructors : rd.declaredConstructors;
if (publicConstructors != null) {
res = publicConstructors.get();
}
} else {
if (declaredConstructors != null) {
res = declaredConstructors.get();
}
}
if (res != null) return res; if (res != null) return res;
} }
// No cached value available; request value from VM // No cached value available; request value from VM
...@@ -2404,11 +2436,11 @@ public final ...@@ -2404,11 +2436,11 @@ public final
} else { } else {
res = getDeclaredConstructors0(publicOnly); res = getDeclaredConstructors0(publicOnly);
} }
if (useCaches) { if (rd != null) {
if (publicOnly) { if (publicOnly) {
publicConstructors = new SoftReference<>(res); rd.publicConstructors = res;
} else { } else {
declaredConstructors = new SoftReference<>(res); rd.declaredConstructors = res;
} }
} }
return res; return res;
...@@ -2425,27 +2457,19 @@ public final ...@@ -2425,27 +2457,19 @@ public final
// via ReflectionFactory.copyMethod. // via ReflectionFactory.copyMethod.
private Method[] privateGetDeclaredMethods(boolean publicOnly) { private Method[] privateGetDeclaredMethods(boolean publicOnly) {
checkInitted(); checkInitted();
Method[] res = null; Method[] res;
if (useCaches) { ReflectionData<T> rd = reflectionData();
clearCachesOnClassRedefinition(); if (rd != null) {
if (publicOnly) { res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
if (declaredPublicMethods != null) {
res = declaredPublicMethods.get();
}
} else {
if (declaredMethods != null) {
res = declaredMethods.get();
}
}
if (res != null) return res; if (res != null) return res;
} }
// No cached value available; request value from VM // No cached value available; request value from VM
res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly)); res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
if (useCaches) { if (rd != null) {
if (publicOnly) { if (publicOnly) {
declaredPublicMethods = new SoftReference<>(res); rd.declaredPublicMethods = res;
} else { } else {
declaredMethods = new SoftReference<>(res); rd.declaredMethods = res;
} }
} }
return res; return res;
...@@ -2547,12 +2571,10 @@ public final ...@@ -2547,12 +2571,10 @@ public final
// via ReflectionFactory.copyMethod. // via ReflectionFactory.copyMethod.
private Method[] privateGetPublicMethods() { private Method[] privateGetPublicMethods() {
checkInitted(); checkInitted();
Method[] res = null; Method[] res;
if (useCaches) { ReflectionData<T> rd = reflectionData();
clearCachesOnClassRedefinition(); if (rd != null) {
if (publicMethods != null) { res = rd.publicMethods;
res = publicMethods.get();
}
if (res != null) return res; if (res != null) return res;
} }
...@@ -2560,7 +2582,7 @@ public final ...@@ -2560,7 +2582,7 @@ public final
// Start by fetching public declared methods // Start by fetching public declared methods
MethodArray methods = new MethodArray(); MethodArray methods = new MethodArray();
{ {
Method[] tmp = privateGetDeclaredMethods(true); Method[] tmp = privateGetDeclaredMethods(true);
methods.addAll(tmp); methods.addAll(tmp);
} }
// Now recur over superclass and direct superinterfaces. // Now recur over superclass and direct superinterfaces.
...@@ -2600,8 +2622,8 @@ public final ...@@ -2600,8 +2622,8 @@ public final
methods.addAllIfNotPresent(inheritedMethods); methods.addAllIfNotPresent(inheritedMethods);
methods.compactAndTrim(); methods.compactAndTrim();
res = methods.getArray(); res = methods.getArray();
if (useCaches) { if (rd != null) {
publicMethods = new SoftReference<>(res); rd.publicMethods = res;
} }
return res; return res;
} }
...@@ -2611,7 +2633,7 @@ public final ...@@ -2611,7 +2633,7 @@ public final
// Helpers for fetchers of one field, method, or constructor // Helpers for fetchers of one field, method, or constructor
// //
private Field searchFields(Field[] fields, String name) { private static Field searchFields(Field[] fields, String name) {
String internedName = name.intern(); String internedName = name.intern();
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
if (fields[i].getName() == internedName) { if (fields[i].getName() == internedName) {
...@@ -2629,7 +2651,7 @@ public final ...@@ -2629,7 +2651,7 @@ public final
// of Field objects which have to be created for the common // of Field objects which have to be created for the common
// case where the field being requested is declared in the // case where the field being requested is declared in the
// class which is being queried. // class which is being queried.
Field res = null; Field res;
// Search declared public fields // Search declared public fields
if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) { if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) {
return res; return res;
...@@ -2681,7 +2703,7 @@ public final ...@@ -2681,7 +2703,7 @@ public final
// number of Method objects which have to be created for the // number of Method objects which have to be created for the
// common case where the method being requested is declared in // common case where the method being requested is declared in
// the class which is being queried. // the class which is being queried.
Method res = null; Method res;
// Search declared public methods // Search declared public methods
if ((res = searchMethods(privateGetDeclaredMethods(true), if ((res = searchMethods(privateGetDeclaredMethods(true),
name, name,
...@@ -3125,9 +3147,20 @@ public final ...@@ -3125,9 +3147,20 @@ public final
// Annotations cache // Annotations cache
private transient Map<Class<? extends Annotation>, Annotation> annotations; private transient Map<Class<? extends Annotation>, Annotation> annotations;
private transient Map<Class<? extends Annotation>, Annotation> declaredAnnotations; private transient Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
// Value of classRedefinedCount when we last cleared the cached annotations and declaredAnnotations fields
private transient int lastAnnotationsRedefinedCount = 0;
// Clears cached values that might possibly have been obsoleted by
// a class redefinition.
private void clearAnnotationCachesOnClassRedefinition() {
if (lastAnnotationsRedefinedCount != classRedefinedCount) {
annotations = declaredAnnotations = null;
lastAnnotationsRedefinedCount = classRedefinedCount;
}
}
private synchronized void initAnnotationsIfNecessary() { private synchronized void initAnnotationsIfNecessary() {
clearCachesOnClassRedefinition(); clearAnnotationCachesOnClassRedefinition();
if (annotations != null) if (annotations != null)
return; return;
declaredAnnotations = AnnotationParser.parseAnnotations( declaredAnnotations = AnnotationParser.parseAnnotations(
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册