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