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