code: package edu.berkeley.nlp.util;
  
  import java.lang.annotation.ElementType;
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  import java.lang.annotation.Target;
  import java.lang.reflect.Field;
  import java.util.ArrayList;
  import java.util.List;
  
  public class SystemUtils {
  
  	@Retention(RetentionPolicy.RUNTIME)
  	@Target(ElementType.FIELD)
  	public @interface SkipMemoryCount {
  	}
  
  	/**
  	 * Counts the memory of the object and everything it points to. Does not
  	 * count static fields.
  	 * 
  	 * @param o
  	 * @return
  	 */
  	public static long countApproximateMemoryUsage(Object... o) {
  		try {
  			final IdentityHashSet<Object> identityHashSet = new IdentityHashSet<Object>();
  			long sum = 0;
  			for (Object obj : o) {
  				sum += countApproximateMemoryUsage(obj, identityHashSet);
  			}
  			return sum;
  		} catch (IllegalArgumentException e) {
  			// TODO Auto-generated catch block
  			throw new RuntimeException(e);
  
  		} catch (IllegalAccessException e) {
  			// TODO Auto-generated catch block
  			throw new RuntimeException(e);
  
  		}
  	}
  
  	private static long countApproximateMemoryUsage(Object o,
  			IdentityHashSet<Object> identityHashSet)
  			throws IllegalArgumentException, IllegalAccessException {
  		if (o == null || identityHashSet.contains(o))
  			return 0;
  		identityHashSet.add(o);
  		Class thisType = o.getClass();
  		// object overhead is 8 bytes
  		long sum = 8;
  
  		if (thisType.isArray()) {
  			if (thisType == byte[].class) {
  				sum += 1 * ((byte[]) o).length;
  			} else if (thisType == boolean[].class) {
  				sum += 1 * ((boolean[]) o).length;
  			} else if (thisType == short[].class) {
  				sum += 2 * ((short[]) o).length;
  			} else if (thisType == char[].class) {
  				sum += 2 * ((char[]) o).length;
  			} else if (thisType == int[].class) {
  				sum += 4 * ((int[]) o).length;
  			} else if (thisType == double[].class) {
  				sum += 8 * ((double[]) o).length;
  			} else if (thisType == long[].class) {
  				sum += 8 * ((long[]) o).length;
  			} else if (thisType == float[].class) {
  				sum += 4 * ((float[]) o).length;
  			} else {
  				// an array objects
  				for (Object o2 : (Object[]) o) {
  					sum += countApproximateMemoryUsage(o2, identityHashSet);
  				}
  			}
  		}
  
  		long fieldSum = 0;
  		List<Class> list = new ArrayList<Class>();
  		Class c = o.getClass();
  		list.add(c);
  		while (c.getSuperclass() != null) {
  			c = c.getSuperclass();
  			list.add(c);
  		}
  		for (Class cl : list) {
  			for (Field field : cl.getDeclaredFields()) {
  				if (java.lang.reflect.Modifier.isStatic(field.getModifiers()))
  					continue;
  				final Class<?> type = field.getType();
  				field.setAccessible(true);
  				if (type.isPrimitive()) {
  					if (type == long.class || type == double.class) {
  						fieldSum += 8;
  					} else {
  						fieldSum += 4;
  					}
  				} else {
  					// for the pointer
  					fieldSum += 4;
  					if (!field.isSynthetic()
  							&& !field
  									.isAnnotationPresent(SkipMemoryCount.class)) {
  						final Object object = field.get(o);
  						if (Thread.currentThread().getStackTrace().length > 50) {
  							//
  							throw new OutOfMemoryError(
  									"measuring memory usage used too much stack");
  						}
  						sum += countApproximateMemoryUsage(object,
  								identityHashSet);
  					}
  
  				}
  
  			}
  		}
  
  		if (fieldSum % 8 != 0) {
  			fieldSum += 4;
  		}
  		return sum + fieldSum;
  
  	}
  
  	public static void main(String[] argv) {
  
  		final Object testObject = new Object() {
  			short[] x = new short[100];
  
  			String[] y = new String[] { "xx", "yy" };
  		};
  		Object testObject2 = new Object() {
  
  			Object o = testObject;
  		};
  
  		System.out
  				.println(countApproximateMemoryUsage(testObject, testObject2));
  		System.out.println(countApproximateMemoryUsage(new Integer(1)));
  
  	}
  
  }
  