--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.iapi.services.cache.ClassSize\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.iapi.services.cache;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import java.lang.Class;\r
+import java.lang.reflect.Field;\r
+import java.lang.Runtime;\r
+import java.lang.InterruptedException;\r
+import java.lang.reflect.Modifier;\r
+\r
+public class ClassSize\r
+{\r
+ public static final int refSize;\r
+ private static final int objectOverhead = 2; // references, not bytes!\r
+ private static final int booleanSize = 4;\r
+ private static final int charSize = 4; // Unicode\r
+ private static final int shortSize = 4;\r
+ private static final int intSize = 4;\r
+ private static final int longSize = 8;\r
+ private static final int floatSize = 4;\r
+ private static final int doubleSize = 8;\r
+ private static final int minObjectSize;\r
+\r
+ private static boolean dummyCatalog = false; // Used when constructing the catalog to prevent recursion\r
+\r
+ static boolean noGuess = false;\r
+ // noGuess is used in unit testing.\r
+\r
+ static boolean unitTest = false;\r
+ // unitTest is used in unit testing\r
+\r
+ private static final int[] wildGuess = {0,16};\r
+ /* The standard wild guess of the size of an unknown class, the size of 16 references.\r
+ * Used when the security manager will not let us look at the class fields.\r
+ */\r
+\r
+ /* Do not let the compiler see ClassSizeCatalog. Otherwise it will try to\r
+ * compile it. This may fail because ClassSizeCatalog.java is not created\r
+ * until everything else has been compiled. Bury ClassSizeCatalog in a string.\r
+ */\r
+ private static java.util.Hashtable catalog;\r
+ static\r
+ {\r
+ try\r
+ {\r
+ catalog = (java.util.Hashtable)\r
+ Class.forName( "org.apache.derby.iapi.services.cache.ClassSizeCatalog").newInstance();\r
+ //Added by Jeff Huang\r
+ catalog = new org.apache.derby.iapi.services.cache.ClassSizeCatalog();\r
+ }\r
+ catch( Exception e){};\r
+\r
+ // Figure out whether this is a 32 or 64 bit machine.\r
+ Runtime runtime = Runtime.getRuntime();\r
+ long memBase = runtime.totalMemory() - runtime.freeMemory();\r
+ Object[] junk = new Object[10000];\r
+ long memUsed = runtime.totalMemory() - runtime.freeMemory() - memBase;\r
+ int sz = (int)((memUsed + junk.length/2)/junk.length);\r
+ refSize = ( 4 > sz) ? 4 : sz;\r
+ minObjectSize = 4*refSize;\r
+ }\r
+\r
+ /**\r
+ * do not try to use the catalog.\r
+ */\r
+ public static void setDummyCatalog()\r
+ {\r
+ dummyCatalog = true;\r
+ }\r
+ /**\r
+ * Get the estimate of the size of an object reference.\r
+ *\r
+ * @return the estimate in bytes.\r
+ */\r
+ public static int getRefSize()\r
+ {\r
+ return refSize;\r
+ }\r
+\r
+ /**\r
+ * @return the estimate of the size of a primitive int\r
+ */\r
+ public static int getIntSize()\r
+ {\r
+ return intSize;\r
+ }\r
+\r
+ /**\r
+ * The estimate of the size of a class instance depends on whether the JVM uses 32 or 64\r
+ * bit addresses, that is it depends on the size of an object reference. It is a linear\r
+ * function of the size of a reference, e.g.\r
+ * 24 + 5*r\r
+ * where r is the size of a reference (usually 4 or 8 bytes).\r
+ *\r
+ * This method returns the coefficients of the linear function, e.g. {24, 5} in the above\r
+ * example.\r
+ *\r
+ * @param cl A class whose instance size is to be estimated\r
+ * @return an array of 2 integers. The first integer is the constant part of the function,\r
+ * the second is the reference size coefficient.\r
+ */\r
+ public static int[] getSizeCoefficients( Class cl)\r
+ {\r
+ int[] coeff = {0, objectOverhead};\r
+\r
+\r
+ \r
+ for( ; null != cl; cl = cl.getSuperclass())\r
+ {\r
+ Field[] field = cl.getDeclaredFields();\r
+ if( null != field)\r
+ {\r
+ for( int i = 0; i < field.length; i++)\r
+ {\r
+ if( ! Modifier.isStatic( field[i].getModifiers()))\r
+ {\r
+ Class fieldClass = field[i].getType();\r
+ if( fieldClass.isArray() || ! fieldClass.isPrimitive())\r
+ coeff[1]++;\r
+ else // Is simple primitive\r
+ {\r
+ String name = fieldClass.getName();\r
+\r
+ if( name.equals( "int") || name.equals( "I"))\r
+ coeff[0] += intSize;\r
+ else if( name.equals( "long") || name.equals( "J"))\r
+ coeff[0] += longSize;\r
+ else if( name.equals( "boolean") || name.equals( "Z"))\r
+ coeff[0] += booleanSize;\r
+ else if( name.equals( "short") || name.equals( "S"))\r
+ coeff[0] += shortSize;\r
+ else if( name.equals( "byte") || name.equals( "B"))\r
+ coeff[0] += 1;\r
+ else if( name.equals( "char") || name.equals( "C"))\r
+ coeff[0] += charSize;\r
+ else if( name.equals( "float") || name.equals( "F"))\r
+ coeff[0] += floatSize;\r
+ else if( name.equals( "double") || name.equals( "D"))\r
+ coeff[0] += doubleSize;\r
+ else // What is this??\r
+ coeff[1]++; // Make a guess: one reference (?)\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return coeff;\r
+ } // end of getSizeCoefficients\r
+\r
+ /**\r
+ * Estimate the static space taken up by a class instance given the coefficients\r
+ * returned by getSizeCoefficients.\r
+ *\r
+ * @param coeff the coefficients\r
+ *\r
+ * @return the size estimate, in bytes\r
+ */\r
+ public static int estimateBaseFromCoefficients( int[] coeff)\r
+ {\r
+ int size = coeff[0] + coeff[1]*refSize;\r
+ // Round up to a multiple of 8\r
+ size = (size + 7)/8;\r
+ size *= 8;\r
+ return (size < minObjectSize) ? minObjectSize : size;\r
+ } // end of estimateBaseFromCoefficients\r
+\r
+ /**\r
+ * Estimate the static space taken up by a class instance from cataloged coefficients.\r
+ *\r
+ * @param cls the class\r
+ *\r
+ * @return the size estimate, in bytes\r
+ *\r
+ * @see #estimateBaseFromCoefficients\r
+ * @see #getSizeCoefficients\r
+ * see org.apache.derbyBuild.ClassSizeCrawler\r
+ */\r
+ public static int estimateBaseFromCatalog( Class cls)\r
+ {\r
+ return estimateBaseFromCatalog( cls, false);\r
+ }\r
+ \r
+ private static int estimateBaseFromCatalog( Class cls, boolean addToCatalog)\r
+ {\r
+ if( dummyCatalog)\r
+ return 0;\r
+ \r
+ if( SanityManager.DEBUG)\r
+ SanityManager.ASSERT( catalog != null, "The class size catalog could not be initialized.");\r
+ \r
+ int[] coeff = (int[]) catalog.get( cls.getName());\r
+ if( coeff == null)\r
+ {\r
+ try\r
+ {\r
+ coeff = getSizeCoefficients( cls);\r
+ }\r
+ catch( Throwable t)\r
+ {\r
+ if( noGuess)\r
+ return -2;\r
+ coeff = wildGuess;\r
+ }\r
+ if( addToCatalog)\r
+ catalog.put( cls.getName(), coeff);\r
+ }\r
+ return estimateBaseFromCoefficients( coeff);\r
+ } // end of estimateBaseFromCatalog\r
+\r
+\r
+ /**\r
+ * Estimate the static space taken up by a class instance. Save the coefficients\r
+ * in a catalog.\r
+ *\r
+ * @param cls the class\r
+ *\r
+ * @return the size estimate, in bytes\r
+ *\r
+ * @see #estimateBaseFromCoefficients\r
+ * @see #getSizeCoefficients\r
+ * see org.apache.derbyBuild.ClassSizeCrawler\r
+ */\r
+ public static int estimateAndCatalogBase( Class cls)\r
+ {\r
+ return estimateBaseFromCatalog( cls, true);\r
+ } // end of estimateAndCatalogBase\r
+\r
+ /**\r
+ * Estimate the static space taken up by the fields of a class. This includes the space taken\r
+ * up by by references (the pointer) but not by the referenced object. So the estimated\r
+ * size of an array field does not depend on the size of the array. Similarly the size of\r
+ * an object (reference) field does not depend on the object.\r
+ *\r
+ * @return the size estimate in bytes.\r
+ *\r
+ * Note that this method will throw a SecurityException if the SecurityManager does not\r
+ * let this class execute the method Class.getDeclaredFields(). If this is a concern try\r
+ * to compute the size coefficients at build time.\r
+ * see org.apache.derbyBuild.ClassSizeCrawler\r
+ * @see #estimateBaseFromCatalog\r
+ */\r
+ public static int estimateBase( Class cl)\r
+ {\r
+ return estimateBaseFromCoefficients( getSizeCoefficients( cl));\r
+ } // End of estimateBase\r
+\r
+ /**\r
+ * @return the estimated overhead of an array. The estimated size of an x[n] array is\r
+ * estimateArrayOverhead() + n*sizeOf(x).\r
+ */\r
+ public static int estimateArrayOverhead()\r
+ {\r
+ return minObjectSize;\r
+ }\r
+ \r
+ /**\r
+ * Estimate the size of a Hashtable entry. In Java 1.2 we can use Map.entry, but this is not\r
+ * available in earlier versions of Java.\r
+ *\r
+ * @return the estimate, in bytes\r
+ */\r
+ public static int estimateHashEntrySize()\r
+ {\r
+ return objectOverhead + 3*refSize;\r
+ }\r
+\r
+ /**\r
+ * Estimate the size of a string.\r
+ *\r
+ * @return the estimated size, in bytes\r
+ */\r
+ public static int estimateMemoryUsage( String str)\r
+ {\r
+ if( null == str)\r
+ return 0;\r
+ // Since Java uses Unicode assume that each character takes 2 bytes\r
+ return 2*str.length();\r
+ }\r
+}\r