2024年1月21日发(作者:)

{ = name; = type; ts = contents; = offset; = length; ize = arraySize; ase = arrayBase; lementSize = arrayElementSize; children = new ArrayList( 1 ); }

public void addChild( final ObjectInfo info ) { if ( info != null ) ( info ); }

/** * Get the full amount of memory occupied by a given object. This value may be slightly less than * an actual value because we don't worry about memory alignment - possible padding after the last object field. * * The result is equal to the last field offset + last field length + all array sizes + all child objects deep sizes * @return Deep object size */ public long getDeepSize() { //return length + arraySize + getUnderlyingSize( arraySize != 0 ); return addPaddingSize(arraySize + getUnderlyingSize( arraySize != 0 )); }

long size = 0;

private long getUnderlyingSize( final boolean isArray ) { //long size = 0; for ( final ObjectInfo child : children ) size += ize + erlyingSize( ize != 0 ); if ( !isArray && !y() ){ int tempSize = ( () - 1 ).offset + ( () - 1 ).length; size += addPaddingSize(tempSize); }

return size; }

private static final class OffsetComparator implements Comparator { @Override public int compare( final ObjectInfo o1, final ObjectInfo o2 ) { return - ; //safe because offsets are small non-negative numbers } }

//sort all children by their offset public void sort() { ( children, new OffsetComparator() ); }

@Override public String toString() { final StringBuilder sb = new StringBuilder(); toStringHelper( sb, 0 ); return ng();

}

private void toStringHelper( final StringBuilder sb, final int depth ) { depth( sb, depth ).append("name=").append( name ).append(", type=").append( type ) .append( ", contents=").append( contents ).append(", offset=").append( offset ) .append(", length=").append( length ); if ( arraySize > 0 ) { (", arrayBase=").append( arrayBase ); (", arrayElemSize=").append( arrayElementSize ); ( ", arraySize=").append( arraySize ); } for ( final ObjectInfo child : children ) { ( 'n' ); ngHelper(sb, depth + 1); } }

private StringBuilder depth( final StringBuilder sb, final int depth ) { for ( int i = 0; i < depth; ++i ) ( "t"); return sb; }

private long addPaddingSize(long size){ if(size % 8 != 0){ return (size / 8 + 1) * 8; } return size; }

}package test;import ;import ;import er;import ist;import ;import tions;import p;import tyHashMap;import ;import ;import ;/** * This class could be used for any object contents/memory layout printing. */public class ClassIntrospector { private static final Unsafe unsafe; /** Size of any Object reference */ private static final int objectRefSize; static { try { Field field = laredField("theUnsafe"); essible(true); unsafe = (Unsafe) (null);

objectRefSize = ndexScale(Object[].class); } catch (Exception e) { throw new RuntimeException(e); } } /** Sizes of all primitive values */ private static final Map primitiveSizes; static { primitiveSizes = new HashMap(10); (, 1); (, 2); (, 4); (, 8); (, 4); (, 8); (, 1); } /** * Get object information for any Java object. Do not pass primitives to * this method because they will boxed and the information you will get will * be related to a boxed version of your value. *

* @param obj * Object to introspect * @return Object info * @throws IllegalAccessException */ public ObjectInfo introspect(final Object obj) throws IllegalAccessException { try { return introspect(obj, null); } finally { // clean visited cache before returning in order to make // this object reusable m_(); } } // we need to keep track of already visited objects in order to support // cycles in the object graphs private IdentityHashMap m_visited = new IdentityHashMap( 100); private ObjectInfo introspect(final Object obj, final Field fld) throws IllegalAccessException { // use Field type only if the field contains null. In this case we will // at least know what's expected to be // stored in this field. Otherwise, if a field has interface type, we // won't see what's really stored in it. // Besides, we should be careful about primitives, because they are // passed as boxed values in this method // (first arg is object) - for them we should still rely on the field // type. boolean isPrimitive = fld != null && e().isPrimitive(); boolean isRecursive = false; // will be set to true if we have already // seen this object if (!isPrimitive) { if (m_nsKey(obj)) isRecursive = true; m_(obj, true); }

final Class type = (fld == null || (obj != null && !isPrimitive)) ? obj .getClass() : e(); int arraySize = 0; int baseOffset = 0; int indexScale = 0; if (y() && obj != null) { baseOffset = aseOffset(type); indexScale = ndexScale(type); arraySize = baseOffset + indexScale * gth(obj); } final ObjectInfo root; if (fld == null) { root = new ObjectInfo("", onicalName(), getContents(obj, type), 0, getShallowSize(type), arraySize, baseOffset, indexScale); } else { final int offset = (int) FieldOffset(fld); root = new ObjectInfo(e(), onicalName(), getContents(obj, type), offset, getShallowSize(type), arraySize, baseOffset, indexScale); } if (!isRecursive && obj != null) { if (isObjectArray(type)) { // introspect object arrays final Object[] ar = (Object[]) obj; for (final Object item : ar) if (item != null) ld(introspect(item, null)); } else { for (final Field field : getAllFields(type)) { if ((ifiers() & ) != 0) { continue; } essible(true); ld(introspect((obj), field)); } } } (); // sort by offset return root; } // get all fields for this class, including all superclasses fields private static List getAllFields(final Class type) { if (itive()) return ist(); Class cur = type; final List res = new ArrayList(10); while (true) { (res, laredFields()); if (cur == ) break; cur = erclass(); } return res; } // check if it is an array of objects. I suspect there must be a more // API-friendly way to make this check. private static boolean isObjectArray(final Class type) { if (!y()) return false;