View Javadoc

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 }