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 private static final boolean JDK7;
104 static {
105 final String version = System.getProperty("java.version");
106
107 if (!version.matches("\\d\\.\\d\\..*")) {
108 throw new RuntimeException("Unexpected version format: " + version);
109 }
110
111 int major = (int) (version.charAt(0) - '0');
112 int minor = (int) (version.charAt(2) - '0');
113 JDK7 = major == 1 && minor == 7;
114 }
115
116
117
118
119
120 static {
121
122 if (is32BitJVM()) {
123 REFERENCE = 4;
124 } else {
125 REFERENCE = 8;
126 }
127
128 OBJECT = 2 * REFERENCE;
129
130 ARRAY = align(3 * REFERENCE);
131
132 ARRAYLIST = align(OBJECT + align(REFERENCE) + align(ARRAY) +
133 (2 * Bytes.SIZEOF_INT));
134
135
136 BYTE_BUFFER = align(OBJECT + align(REFERENCE) + align(ARRAY) +
137 (5 * Bytes.SIZEOF_INT) +
138 (3 * Bytes.SIZEOF_BOOLEAN) + Bytes.SIZEOF_LONG);
139
140 INTEGER = align(OBJECT + Bytes.SIZEOF_INT);
141
142 MAP_ENTRY = align(OBJECT + 5 * REFERENCE + Bytes.SIZEOF_BOOLEAN);
143
144 TREEMAP = align(OBJECT + (2 * Bytes.SIZEOF_INT) + align(7 * REFERENCE));
145
146
147
148 STRING = (int) estimateBase(String.class, false);
149
150
151
152
153 CONCURRENT_HASHMAP = (int) estimateBase(ConcurrentHashMap.class, false);
154
155 CONCURRENT_HASHMAP_ENTRY = align(REFERENCE + OBJECT + (3 * REFERENCE) +
156 (2 * Bytes.SIZEOF_INT));
157
158 CONCURRENT_HASHMAP_SEGMENT = align(REFERENCE + OBJECT +
159 (3 * Bytes.SIZEOF_INT) + Bytes.SIZEOF_FLOAT + ARRAY);
160
161 CONCURRENT_SKIPLISTMAP = align(Bytes.SIZEOF_INT + OBJECT + (8 * REFERENCE));
162
163 CONCURRENT_SKIPLISTMAP_ENTRY = align(
164 align(OBJECT + (3 * REFERENCE)) +
165 align((OBJECT + (3 * REFERENCE))/2));
166
167 REENTRANT_LOCK = align(OBJECT + (3 * REFERENCE));
168
169 ATOMIC_LONG = align(OBJECT + Bytes.SIZEOF_LONG);
170
171 ATOMIC_INTEGER = align(OBJECT + Bytes.SIZEOF_INT);
172
173 ATOMIC_BOOLEAN = align(OBJECT + Bytes.SIZEOF_BOOLEAN);
174
175 COPYONWRITE_ARRAYSET = align(OBJECT + REFERENCE);
176
177 COPYONWRITE_ARRAYLIST = align(OBJECT + (2 * REFERENCE) + ARRAY);
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195 @SuppressWarnings("unchecked")
196 private static int [] getSizeCoefficients(Class cl, boolean debug) {
197 int primitives = 0;
198 int arrays = 0;
199
200 int references = nrOfRefsPerObj;
201 int index = 0;
202
203 for ( ; null != cl; cl = cl.getSuperclass()) {
204 Field[] field = cl.getDeclaredFields();
205 if (null != field) {
206 for (Field aField : field) {
207 if (Modifier.isStatic(aField.getModifiers())) continue;
208 Class fieldClass = aField.getType();
209 if (fieldClass.isArray()) {
210 arrays++;
211 references++;
212 } else if (!fieldClass.isPrimitive()) {
213 references++;
214 } else {
215 String name = fieldClass.getName();
216
217 if (name.equals("int") || name.equals("I"))
218 primitives += Bytes.SIZEOF_INT;
219 else if (name.equals("long") || name.equals("J"))
220 primitives += Bytes.SIZEOF_LONG;
221 else if (name.equals("boolean") || name.equals("Z"))
222 primitives += Bytes.SIZEOF_BOOLEAN;
223 else if (name.equals("short") || name.equals("S"))
224 primitives += Bytes.SIZEOF_SHORT;
225 else if (name.equals("byte") || name.equals("B"))
226 primitives += Bytes.SIZEOF_BYTE;
227 else if (name.equals("char") || name.equals("C"))
228 primitives += Bytes.SIZEOF_CHAR;
229 else if (name.equals("float") || name.equals("F"))
230 primitives += Bytes.SIZEOF_FLOAT;
231 else if (name.equals("double") || name.equals("D"))
232 primitives += Bytes.SIZEOF_DOUBLE;
233 }
234 if (debug) {
235 if (LOG.isDebugEnabled()) {
236
237 LOG.debug("" + index + " " + aField.getName() + " " + aField.getType());
238 }
239 }
240 index++;
241 }
242 }
243 }
244 return new int [] {primitives, arrays, references};
245 }
246
247
248
249
250
251
252
253
254
255
256 private static long estimateBaseFromCoefficients(int [] coeff, boolean debug) {
257 long prealign_size = coeff[0] + align(coeff[1] * ARRAY) + coeff[2] * REFERENCE;
258
259
260 long size = align(prealign_size);
261 if(debug) {
262 if (LOG.isDebugEnabled()) {
263
264 LOG.debug("Primitives=" + coeff[0] + ", arrays=" + coeff[1] +
265 ", references(includes " + nrOfRefsPerObj +
266 " for object overhead)=" + coeff[2] + ", refSize " + REFERENCE +
267 ", size=" + size + ", prealign_size=" + prealign_size);
268 }
269 }
270 return size;
271 }
272
273
274
275
276
277
278
279
280
281
282
283
284 @SuppressWarnings("unchecked")
285 public static long estimateBase(Class cl, boolean debug) {
286 return estimateBaseFromCoefficients( getSizeCoefficients(cl, debug), debug);
287 }
288
289
290
291
292
293
294 public static int align(int num) {
295 return (int)(align((long)num));
296 }
297
298
299
300
301
302
303 public static long align(long num) {
304
305
306 return ((num + 7) >> 3) << 3;
307 }
308
309
310
311
312
313 public static boolean is32BitJVM() {
314 return System.getProperty("sun.arch.data.model").equals("32");
315 }
316
317 }
318