1 package net.sf.ehcache.pool.sizeof;
2
3 import net.sf.ehcache.pool.sizeof.JvmInformation;
4 import net.sf.ehcache.pool.sizeof.SizeOf;
5 import net.sf.ehcache.pool.sizeof.SizeOfAgent;
6
7 import org.junit.Assume;
8 import org.junit.BeforeClass;
9 import org.junit.Test;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.atomic.AtomicLong;
14 import java.util.concurrent.locks.ReentrantReadWriteLock;
15
16 import static org.hamcrest.CoreMatchers.equalTo;
17 import static org.hamcrest.CoreMatchers.is;
18 import static org.junit.Assert.assertThat;
19
20 /***
21 * @author Alex Snaps
22 */
23 public class SizeOfTest extends AbstractSizeOfTest {
24
25 public Object[] container;
26
27 @BeforeClass
28 public static void setup() {
29 new CrossCheckingSizeOf().deepSizeOf(new EvilPair(new Object(), new SomeClass(true)));
30 System.err.println("Testing for a " + System.getProperty("java.version") + " JDK on a "
31 + System.getProperty("sun.arch.data.model") + "bit VM (compressed-oops: " + COMPRESSED_OOPS + ")");
32 }
33
34 @Test
35 public void testSizeOf() throws Exception {
36 Assume.assumeThat(JvmInformation.MINIMUM_OBJECT_SIZE, is(JvmInformation.OBJECT_ALIGNMENT));
37
38 SizeOf sizeOf = new CrossCheckingSizeOf();
39 if (System.getProperty("java.version").startsWith("1.5")) {
40 if (System.getProperty("sun.arch.data.model").equals("64")) {
41 verify64bitSizes(sizeOf);
42 assertThat(sizeOf.deepSizeOf(new ReentrantReadWriteLock()), is(136L));
43 } else {
44 verify32bitSizes(sizeOf);
45 assertThat(sizeOf.deepSizeOf(new ReentrantReadWriteLock()), is(80L));
46 }
47 } else {
48 if (System.getProperty("sun.arch.data.model").equals("64")) {
49 if (COMPRESSED_OOPS) {
50 verify64bitCompressedOopsSizes(sizeOf);
51 assertThat(sizeOf.deepSizeOf(new ReentrantReadWriteLock()), is(112L));
52 } else {
53 verify64bitSizes(sizeOf);
54 assertThat(sizeOf.deepSizeOf(new ReentrantReadWriteLock()), is(176L));
55 }
56 } else {
57 verify32bitSizes(sizeOf);
58 assertThat(sizeOf.deepSizeOf(new ReentrantReadWriteLock()), is(104L));
59 }
60 }
61
62 List<Object> list1 = new ArrayList<Object>();
63 List<Object> list2 = new ArrayList<Object>();
64
65 Object someInstance = new Object();
66 list1.add(someInstance);
67 list2.add(someInstance);
68
69 assertThat(sizeOf.deepSizeOf(list1), equalTo(sizeOf.deepSizeOf(list2)));
70 assertThat(sizeOf.deepSizeOf(list1, list2) < (sizeOf.deepSizeOf(list1) + sizeOf.deepSizeOf(list2)), is(true));
71 list2.add(new Object());
72 assertThat(sizeOf.deepSizeOf(list2) > sizeOf.deepSizeOf(list1), is(true));
73 }
74
75 private void verify32bitSizes(SizeOf sizeOf) {
76 assertThat(sizeOf.sizeOf(new Object()), is(8L));
77 assertThat(sizeOf.sizeOf(1), equalTo(0L));
78 assertThat(sizeOf.sizeOf(new Integer(1)), is(16L));
79 assertThat(sizeOf.sizeOf(new Integer(1)), is(sizeOf.deepSizeOf(new Integer(1))));
80 assertThat(sizeOf.sizeOf(1000), is(16L));
81 assertThat(sizeOf.deepSizeOf(new SomeClass(false)), is(16L));
82 assertThat(sizeOf.deepSizeOf(new SomeClass(true)), is(24L));
83 assertThat(sizeOf.sizeOf(new Object[] { }), is(16L));
84 assertThat(sizeOf.sizeOf(new Object[] { new Object(), new Object(), new Object(), new Object() }), is(32L));
85 assertThat(sizeOf.sizeOf(new int[] { }), is(16L));
86 assertThat(sizeOf.sizeOf(new int[] { 987654, 876543, 765432, 654321 }), is(32L));
87 assertThat(sizeOf.deepSizeOf(new Pair(null, null)), is(16L));
88 assertThat(sizeOf.deepSizeOf(new Pair(new Object(), null)), is(24L));
89 assertThat(sizeOf.deepSizeOf(new Pair(new Object(), new Object())), is(32L));
90 }
91
92 private void verify64bitSizes(SizeOf sizeOf) {
93 assertThat(sizeOf.sizeOf(new Object()), is(16L));
94 assertThat(sizeOf.sizeOf(1), equalTo(0L));
95 assertThat(sizeOf.sizeOf(new Integer(1)), is(24L));
96 assertThat(sizeOf.sizeOf(new Integer(1)), is(sizeOf.deepSizeOf(new Integer(1))));
97 assertThat(sizeOf.sizeOf(1000), is(24L));
98 assertThat(sizeOf.deepSizeOf(new SomeClass(false)), is(24L));
99 assertThat(sizeOf.deepSizeOf(new SomeClass(true)), is(40L));
100 assertThat(sizeOf.sizeOf(new Object[] { }), is(24L));
101 assertThat(sizeOf.sizeOf(new Object[] { new Object(), new Object(), new Object(), new Object() }), is(56L));
102 assertThat(sizeOf.sizeOf(new int[] { }), is(24L));
103 assertThat(sizeOf.sizeOf(new int[] { 987654, 876543, 765432, 654321 }), is(40L));
104 assertThat(sizeOf.deepSizeOf(new Pair(null, null)), is(32L));
105 assertThat(sizeOf.deepSizeOf(new Pair(new Object(), null)), is(48L));
106 assertThat(sizeOf.deepSizeOf(new Pair(new Object(), new Object())), is(64L));
107 }
108
109 private void verify64bitCompressedOopsSizes(SizeOf sizeOf) {
110 assertThat(sizeOf.sizeOf(new Object()), is(16L));
111 assertThat(sizeOf.sizeOf(1), equalTo(0L));
112 assertThat(sizeOf.sizeOf(new Integer(1)), is(16L));
113 assertThat(sizeOf.sizeOf(new Integer(1)), is(sizeOf.deepSizeOf(new Integer(1))));
114 assertThat(sizeOf.sizeOf(1000), is(16L));
115 assertThat(sizeOf.deepSizeOf(new SomeClass(false)), is(16L));
116 assertThat(sizeOf.deepSizeOf(new SomeClass(true)), is(32L));
117 assertThat(sizeOf.sizeOf(new Object[] { }), is(16L));
118 assertThat(sizeOf.sizeOf(new Object[] { new Object(), new Object(), new Object(), new Object() }), is(32L));
119 assertThat(sizeOf.sizeOf(new int[] { }), is(16L));
120 assertThat(sizeOf.sizeOf(new int[] { 987654, 876543, 765432, 654321 }), is(32L));
121 assertThat(sizeOf.deepSizeOf(new Pair(null, null)), is(24L));
122 assertThat(sizeOf.deepSizeOf(new Pair(new Object(), null)), is(40L));
123 assertThat(sizeOf.deepSizeOf(new Pair(new Object(), new Object())), is(56L));
124 }
125
126 @Test
127 public void testOnHeapConsumption() throws Exception {
128 SizeOf sizeOf = new CrossCheckingSizeOf();
129
130 int size = 80000;
131
132 for (int j = 0; j < 5; j++) {
133 container = new Object[size];
134 long usedBefore = measureMemoryUse();
135 for (int i = 0; i < size; i++) {
136 container[i] = new EvilPair(new Object(), new SomeClass(i % 2 == 0));
137 }
138
139 long mem = 0;
140 for (Object s : container) {
141 mem += sizeOf.deepSizeOf(s);
142 }
143
144 long used = measureMemoryUse() - usedBefore;
145 float percentage = 1 - (mem / (float) used);
146 System.err.println("Run # " + (j + 1) + ": Deviation of " + (int)(percentage * -100) +
147 "%\n" + used +
148 " bytes are actually being used, while we believe " + mem + " are");
149 if (j > 1) {
150 assertThat("Run # " + (j + 1) + ": Deviation of " + (int)(percentage * -100) +
151 "% was above the +/-1.5% delta threshold \n" + used +
152 " bytes are actually being used, while we believe " + mem + " are (" +
153 (used - mem) / size + ")",
154 Math.abs(percentage) < .015f, is(true));
155 }
156 }
157 }
158
159 private long measureMemoryUse() throws InterruptedException {
160 System.gc();
161 System.gc();
162 System.gc();
163 Thread.sleep(2000);
164 System.gc();
165 System.gc();
166 Thread.sleep(2000);
167 System.gc();
168 System.gc();
169 return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
170 }
171
172 public static class SomeClass {
173
174 public Object ref;
175
176 public SomeClass(final boolean init) {
177 if (init) {
178 ref = new Object();
179 }
180 }
181 }
182
183 @SuppressWarnings("unused")
184 public static class Pair {
185 private final Object one;
186 private final Object two;
187
188 public Pair(final Object one, final Object two) {
189 this.one = one;
190 this.two = two;
191 }
192 }
193
194 @SuppressWarnings("unused")
195 public static final class Stupid {
196
197 public static class internal {
198 private int someValue;
199 private long otherValue;
200 }
201
202 internal internal = new internal();
203 int someValue;
204 long someOther;
205 long otherValue;
206 boolean bool;
207 }
208
209 @SuppressWarnings("unused")
210 public static final class EvilPair extends Pair {
211
212 private static final AtomicLong counter = new AtomicLong(Long.MIN_VALUE);
213
214 private final Object oneHidden;
215 private final Object twoHidden;
216 private final Object copyOne;
217 private final Object copyTwo;
218 private final long instanceNumber;
219
220 private EvilPair(final Object one, final Object two) {
221 super(one, two);
222 instanceNumber = counter.getAndIncrement();
223 if (instanceNumber % 4 == 0) {
224 oneHidden = new Object();
225 twoHidden = new Object();
226 } else {
227 oneHidden = null;
228 twoHidden = null;
229 }
230 this.copyOne = one;
231 this.copyTwo = two;
232 }
233 }
234 }