1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.util;
22
23 import java.lang.reflect.Field;
24 import java.lang.reflect.Modifier;
25
26 import java.util.concurrent.ConcurrentHashMap;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hadoop.classification.InterfaceAudience;
31 import org.apache.hadoop.classification.InterfaceStability;
32
33
34
35
36
37
38
39 @InterfaceAudience.Public
40 @InterfaceStability.Stable
41 public class ClassSize {
42 static final Log LOG = LogFactory.getLog(ClassSize.class);
43
44 private static int nrOfRefsPerObj = 2;
45
46
47 public static final int ARRAY;
48
49
50 public static final int ARRAYLIST;
51
52
53 public static final int BYTE_BUFFER;
54
55
56 public static final int INTEGER;
57
58
59 public static final int MAP_ENTRY;
60
61
62 public static final int OBJECT;
63
64
65 public static final int REFERENCE;
66
67
68 public static final int STRING;
69
70
71 public static final int TREEMAP;
72
73
74 public static final int CONCURRENT_HASHMAP;
75
76
77 public static final int CONCURRENT_HASHMAP_ENTRY;
78
79
80 public static final int CONCURRENT_HASHMAP_SEGMENT;
81
82
83 public static final int CONCURRENT_SKIPLISTMAP;
84
85
86 public static final int CONCURRENT_SKIPLISTMAP_ENTRY;
87
88
89 public static final int REENTRANT_LOCK;
90
91
92 public static final int ATOMIC_LONG;
93
94
95 public static final int ATOMIC_INTEGER;
96
97
98 public static final int ATOMIC_BOOLEAN;
99
100
101 public static final int COPYONWRITE_ARRAYSET;
102
103
104 public static final int COPYONWRITE_ARRAYLIST;
105
106
107 public static final int TIMERANGE;
108
109
110 private static final boolean JDK7;
111 static {
112 final String version = System.getProperty("java.version");
113
114 if (!version.matches("\\d\\.\\d\\..*")) {
115 throw new RuntimeException("Unexpected version format: " + version);
116 }
117
118 int major = (int)(version.charAt(0) - '0');
119 int minor = (int)(version.charAt(2) - '0');
120 JDK7 = major == 1 && minor == 7;
121 }
122
123
124
125
126
127 static {
128
129 if (is32BitJVM()) {
130 REFERENCE = 4;
131 } else {
132 REFERENCE = 8;
133 }
134
135 OBJECT = 2 * REFERENCE;
136
137 ARRAY = align(3 * REFERENCE);
138
139 ARRAYLIST = align(OBJECT + align(REFERENCE) + align(ARRAY) +
140 (2 * Bytes.SIZEOF_INT));
141
142
143 BYTE_BUFFER = align(OBJECT + align(REFERENCE) + align(ARRAY) +
144 (5 * Bytes.SIZEOF_INT) +
145 (3 * Bytes.SIZEOF_BOOLEAN) + Bytes.SIZEOF_LONG);
146
147 INTEGER = align(OBJECT + Bytes.SIZEOF_INT);
148
149 MAP_ENTRY = align(OBJECT + 5 * REFERENCE + Bytes.SIZEOF_BOOLEAN);
150
151 TREEMAP = align(OBJECT + (2 * Bytes.SIZEOF_INT) + align(7 * REFERENCE));
152
153
154
155 STRING = (int) estimateBase(String.class, false);
156
157
158
159
160 CONCURRENT_HASHMAP = (int) estimateBase(ConcurrentHashMap.class, false);
161
162 CONCURRENT_HASHMAP_ENTRY = align(REFERENCE + OBJECT + (3 * REFERENCE) +
163 (2 * Bytes.SIZEOF_INT));
164
165 CONCURRENT_HASHMAP_SEGMENT = align(REFERENCE + OBJECT +
166 (3 * Bytes.SIZEOF_INT) + Bytes.SIZEOF_FLOAT + ARRAY);
167
168 CONCURRENT_SKIPLISTMAP = align(Bytes.SIZEOF_INT + OBJECT + (8 * REFERENCE));
169
170 CONCURRENT_SKIPLISTMAP_ENTRY = align(
171 align(OBJECT + (3 * REFERENCE)) +
172 align((OBJECT + (3 * REFERENCE))/2));
173
174 REENTRANT_LOCK = align(OBJECT + (3 * REFERENCE));
175
176 ATOMIC_LONG = align(OBJECT + Bytes.SIZEOF_LONG);
177
178 ATOMIC_INTEGER = align(OBJECT + Bytes.SIZEOF_INT);
179
180 ATOMIC_BOOLEAN = align(OBJECT + Bytes.SIZEOF_BOOLEAN);
181
182 COPYONWRITE_ARRAYSET = align(OBJECT + REFERENCE);
183
184 COPYONWRITE_ARRAYLIST = align(OBJECT + (2 * REFERENCE) + ARRAY);
185
186 TIMERANGE = align(ClassSize.OBJECT + Bytes.SIZEOF_LONG * 2 + Bytes.SIZEOF_BOOLEAN);
187 }
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204 @SuppressWarnings("unchecked")
205 private static int [] getSizeCoefficients(Class cl, boolean debug) {
206 int primitives = 0;
207 int arrays = 0;
208
209 int references = nrOfRefsPerObj;
210 int index = 0;
211
212 for ( ; null != cl; cl = cl.getSuperclass()) {
213 Field[] field = cl.getDeclaredFields();
214 if (null != field) {
215 for (Field aField : field) {
216 if (Modifier.isStatic(aField.getModifiers())) continue;
217 Class fieldClass = aField.getType();
218 if (fieldClass.isArray()) {
219 arrays++;
220 references++;
221 } else if (!fieldClass.isPrimitive()) {
222 references++;
223 } else {
224 String name = fieldClass.getName();
225
226 if (name.equals("int") || name.equals("I"))
227 primitives += Bytes.SIZEOF_INT;
228 else if (name.equals("long") || name.equals("J"))
229 primitives += Bytes.SIZEOF_LONG;
230 else if (name.equals("boolean") || name.equals("Z"))
231 primitives += Bytes.SIZEOF_BOOLEAN;
232 else if (name.equals("short") || name.equals("S"))
233 primitives += Bytes.SIZEOF_SHORT;
234 else if (name.equals("byte") || name.equals("B"))
235 primitives += Bytes.SIZEOF_BYTE;
236 else if (name.equals("char") || name.equals("C"))
237 primitives += Bytes.SIZEOF_CHAR;
238 else if (name.equals("float") || name.equals("F"))
239 primitives += Bytes.SIZEOF_FLOAT;
240 else if (name.equals("double") || name.equals("D"))
241 primitives += Bytes.SIZEOF_DOUBLE;
242 }
243 if (debug) {
244 if (LOG.isDebugEnabled()) {
245 LOG.debug("" + index + " " + aField.getName() + " " + aField.getType());
246 }
247 }
248 index++;
249 }
250 }
251 }
252 return new int [] {primitives, arrays, references};
253 }
254
255
256
257
258
259
260
261
262
263
264 private static long estimateBaseFromCoefficients(int [] coeff, boolean debug) {
265 long prealign_size = coeff[0] + align(coeff[1] * ARRAY) + coeff[2] * REFERENCE;
266
267
268 long size = align(prealign_size);
269 if(debug) {
270 if (LOG.isDebugEnabled()) {
271 LOG.debug("Primitives=" + coeff[0] + ", arrays=" + coeff[1] +
272 ", references(includes " + nrOfRefsPerObj +
273 " for object overhead)=" + coeff[2] + ", refSize " + REFERENCE +
274 ", size=" + size + ", prealign_size=" + prealign_size);
275 }
276 }
277 return size;
278 }
279
280
281
282
283
284
285
286
287
288
289
290
291 @SuppressWarnings("unchecked")
292 public static long estimateBase(Class cl, boolean debug) {
293 return estimateBaseFromCoefficients( getSizeCoefficients(cl, debug), debug);
294 }
295
296
297
298
299
300
301 public static int align(int num) {
302 return (int)(align((long)num));
303 }
304
305
306
307
308
309
310 public static long align(long num) {
311
312
313 return ((num + 7) >> 3) << 3;
314 }
315
316
317
318
319
320 public static boolean is32BitJVM() {
321 return System.getProperty("sun.arch.data.model").equals("32");
322 }
323
324 }
325