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