001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.io;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertTrue;
022
023import java.io.IOException;
024import java.lang.management.ManagementFactory;
025import java.lang.management.RuntimeMXBean;
026import java.nio.ByteBuffer;
027import java.util.ArrayList;
028import java.util.LinkedList;
029import java.util.Map;
030import java.util.TreeMap;
031import java.util.concurrent.ConcurrentHashMap;
032import java.util.concurrent.ConcurrentSkipListMap;
033import java.util.concurrent.CopyOnWriteArrayList;
034import java.util.concurrent.CopyOnWriteArraySet;
035import java.util.concurrent.atomic.AtomicBoolean;
036import java.util.concurrent.atomic.AtomicInteger;
037import java.util.concurrent.atomic.AtomicLong;
038import java.util.concurrent.atomic.AtomicReference;
039import java.util.concurrent.locks.ReentrantReadWriteLock;
040import org.apache.hadoop.hbase.HBaseClassTestRule;
041import org.apache.hadoop.hbase.KeyValue;
042import org.apache.hadoop.hbase.client.Delete;
043import org.apache.hadoop.hbase.client.Mutation;
044import org.apache.hadoop.hbase.client.Put;
045import org.apache.hadoop.hbase.io.hfile.BlockCacheKey;
046import org.apache.hadoop.hbase.io.hfile.LruBlockCache;
047import org.apache.hadoop.hbase.io.hfile.LruCachedBlock;
048import org.apache.hadoop.hbase.regionserver.CSLMImmutableSegment;
049import org.apache.hadoop.hbase.regionserver.CellArrayImmutableSegment;
050import org.apache.hadoop.hbase.regionserver.CellArrayMap;
051import org.apache.hadoop.hbase.regionserver.CellSet;
052import org.apache.hadoop.hbase.regionserver.CompactingMemStore;
053import org.apache.hadoop.hbase.regionserver.CompactionPipeline;
054import org.apache.hadoop.hbase.regionserver.DefaultMemStore;
055import org.apache.hadoop.hbase.regionserver.HRegion;
056import org.apache.hadoop.hbase.regionserver.HStore;
057import org.apache.hadoop.hbase.regionserver.ImmutableSegment;
058import org.apache.hadoop.hbase.regionserver.MemStoreCompactor;
059import org.apache.hadoop.hbase.regionserver.MutableSegment;
060import org.apache.hadoop.hbase.regionserver.Segment;
061import org.apache.hadoop.hbase.regionserver.TimeRangeTracker.NonSyncTimeRangeTracker;
062import org.apache.hadoop.hbase.regionserver.TimeRangeTracker.SyncTimeRangeTracker;
063import org.apache.hadoop.hbase.regionserver.throttle.StoreHotnessProtector;
064import org.apache.hadoop.hbase.testclassification.IOTests;
065import org.apache.hadoop.hbase.testclassification.SmallTests;
066import org.apache.hadoop.hbase.util.ClassSize;
067import org.junit.BeforeClass;
068import org.junit.ClassRule;
069import org.junit.Test;
070import org.junit.experimental.categories.Category;
071import org.slf4j.Logger;
072import org.slf4j.LoggerFactory;
073
074/**
075 * Testing the sizing that HeapSize offers and compares to the size given by
076 * ClassSize.
077 */
078@Category({IOTests.class, SmallTests.class})
079public class TestHeapSize  {
080
081  @ClassRule
082  public static final HBaseClassTestRule CLASS_RULE =
083      HBaseClassTestRule.forClass(TestHeapSize.class);
084
085  private static final Logger LOG = LoggerFactory.getLogger(TestHeapSize.class);
086  // List of classes implementing HeapSize
087  // BatchOperation, BatchUpdate, BlockIndex, Entry, Entry<K,V>, HStoreKey
088  // KeyValue, LruBlockCache, Put, WALKey
089
090  @BeforeClass
091  public static void beforeClass() throws Exception {
092    // Print detail on jvm so we know what is different should below test fail.
093    RuntimeMXBean b = ManagementFactory.getRuntimeMXBean();
094    LOG.info("name=" + b.getName());
095    LOG.info("specname=" + b.getSpecName());
096    LOG.info("specvendor=" + b.getSpecVendor());
097    LOG.info("vmname=" + b.getVmName());
098    LOG.info("vmversion=" + b.getVmVersion());
099    LOG.info("vmvendor=" + b.getVmVendor());
100    Map<String, String> p = b.getSystemProperties();
101    LOG.info("properties=" + p);
102  }
103
104  /**
105   * Test our hard-coded sizing of native java objects
106   */
107  @Test
108  public void testNativeSizes() throws IOException {
109    Class<?> cl;
110    long expected;
111    long actual;
112
113    // ArrayList
114    cl = ArrayList.class;
115    expected = ClassSize.estimateBase(cl, false);
116    actual = ClassSize.ARRAYLIST;
117    if(expected != actual) {
118      ClassSize.estimateBase(cl, true);
119      assertEquals(expected, actual);
120    }
121
122    // ByteBuffer
123    cl = ByteBuffer.class;
124    expected = ClassSize.estimateBase(cl, false);
125    actual = ClassSize.BYTE_BUFFER;
126    if(expected != actual) {
127      ClassSize.estimateBase(cl, true);
128      assertEquals(expected, actual);
129    }
130
131    // Integer
132    cl = Integer.class;
133    expected = ClassSize.estimateBase(cl, false);
134    actual = ClassSize.INTEGER;
135    if(expected != actual) {
136      ClassSize.estimateBase(cl, true);
137      assertEquals(expected, actual);
138    }
139
140    // Map.Entry
141    // Interface is public, all others are not.  Hard to size via ClassSize
142//    cl = Map.Entry.class;
143//    expected = ClassSize.estimateBase(cl, false);
144//    actual = ClassSize.MAP_ENTRY;
145//    if(expected != actual) {
146//      ClassSize.estimateBase(cl, true);
147//      assertEquals(expected, actual);
148//    }
149
150    // Object
151    cl = Object.class;
152    expected = ClassSize.estimateBase(cl, false);
153    actual = ClassSize.align(ClassSize.OBJECT);
154    if(expected != actual) {
155      ClassSize.estimateBase(cl, true);
156      assertEquals(expected, actual);
157    }
158
159    // TreeMap
160    cl = TreeMap.class;
161    expected = ClassSize.estimateBase(cl, false);
162    actual = ClassSize.TREEMAP;
163    if(expected != actual) {
164      ClassSize.estimateBase(cl, true);
165      assertEquals(expected, actual);
166    }
167
168    // String
169    cl = String.class;
170    expected = ClassSize.estimateBase(cl, false);
171    actual = ClassSize.STRING;
172    if(expected != actual) {
173      ClassSize.estimateBase(cl, true);
174      assertEquals(expected, actual);
175    }
176
177    // ConcurrentHashMap
178    cl = ConcurrentHashMap.class;
179    expected = ClassSize.estimateBase(cl, false);
180    actual = ClassSize.CONCURRENT_HASHMAP;
181    if(expected != actual) {
182      ClassSize.estimateBase(cl, true);
183      assertEquals(expected, actual);
184    }
185
186    // ConcurrentSkipListMap
187    cl = ConcurrentSkipListMap.class;
188    expected = ClassSize.estimateBase(cl, false);
189    actual = ClassSize.CONCURRENT_SKIPLISTMAP;
190    if(expected != actual) {
191      ClassSize.estimateBase(cl, true);
192      assertEquals(expected, actual);
193    }
194
195    // CellArrayMap
196    cl = CellArrayMap.class;
197    expected = ClassSize.estimateBase(cl, false);
198    actual = ClassSize.CELL_ARRAY_MAP;
199    if(expected != actual) {
200      ClassSize.estimateBase(cl, true);
201      assertEquals(expected, actual);
202    }
203
204    // ReentrantReadWriteLock
205    cl = ReentrantReadWriteLock.class;
206    expected = ClassSize.estimateBase(cl, false);
207    actual = ClassSize.REENTRANT_LOCK;
208    if(expected != actual) {
209      ClassSize.estimateBase(cl, true);
210      assertEquals(expected, actual);
211    }
212
213    // AtomicLong
214    cl = AtomicLong.class;
215    expected = ClassSize.estimateBase(cl, false);
216    actual = ClassSize.ATOMIC_LONG;
217    if(expected != actual) {
218      ClassSize.estimateBase(cl, true);
219      assertEquals(expected, actual);
220    }
221
222    // AtomicInteger
223    cl = AtomicInteger.class;
224    expected = ClassSize.estimateBase(cl, false);
225    actual = ClassSize.ATOMIC_INTEGER;
226    if(expected != actual) {
227      ClassSize.estimateBase(cl, true);
228      assertEquals(expected, actual);
229    }
230
231    // AtomicBoolean
232    cl = AtomicBoolean.class;
233    expected = ClassSize.estimateBase(cl, false);
234    actual = ClassSize.ATOMIC_BOOLEAN;
235    if(expected != actual) {
236      ClassSize.estimateBase(cl, true);
237      assertEquals(expected, actual);
238    }
239
240    // CopyOnWriteArraySet
241    cl = CopyOnWriteArraySet.class;
242    expected = ClassSize.estimateBase(cl, false);
243    actual = ClassSize.COPYONWRITE_ARRAYSET;
244    if(expected != actual) {
245      ClassSize.estimateBase(cl, true);
246      assertEquals(expected, actual);
247    }
248
249    // CopyOnWriteArrayList
250    cl = CopyOnWriteArrayList.class;
251    expected = ClassSize.estimateBase(cl, false);
252    actual = ClassSize.COPYONWRITE_ARRAYLIST;
253    if(expected != actual) {
254      ClassSize.estimateBase(cl, true);
255      assertEquals(expected, actual);
256    }
257
258    // SyncTimeRangeTracker
259    cl = SyncTimeRangeTracker.class;
260    expected = ClassSize.estimateBase(cl, false);
261    actual = ClassSize.SYNC_TIMERANGE_TRACKER;
262    if (expected != actual) {
263      ClassSize.estimateBase(cl, true);
264      assertEquals(expected, actual);
265    }
266
267    // NonSyncTimeRangeTracker
268    cl = NonSyncTimeRangeTracker.class;
269    expected = ClassSize.estimateBase(cl, false);
270    actual = ClassSize.NON_SYNC_TIMERANGE_TRACKER;
271    if (expected != actual) {
272      ClassSize.estimateBase(cl, true);
273      assertEquals(expected, actual);
274    }
275
276    // CellSet
277    cl = CellSet.class;
278    expected = ClassSize.estimateBase(cl, false);
279    actual = ClassSize.CELL_SET;
280    if (expected != actual) {
281      ClassSize.estimateBase(cl, true);
282      assertEquals(expected, actual);
283    }
284  }
285
286  /**
287   * Testing the classes that implements HeapSize and are a part of 0.20.
288   * Some are not tested here for example BlockIndex which is tested in
289   * TestHFile since it is a non public class
290   * @throws IOException
291   */
292  @Test
293  public void testSizes() throws IOException {
294    Class<?> cl;
295    long expected;
296    long actual;
297
298    //KeyValue
299    cl = KeyValue.class;
300    expected = ClassSize.estimateBase(cl, false);
301    KeyValue kv = new KeyValue();
302    actual = kv.heapSize();
303    if(expected != actual) {
304      ClassSize.estimateBase(cl, true);
305      assertEquals(expected, actual);
306    }
307
308    //LruBlockCache Overhead
309    cl = LruBlockCache.class;
310    actual = LruBlockCache.CACHE_FIXED_OVERHEAD;
311    expected = ClassSize.estimateBase(cl, false);
312    if(expected != actual) {
313      ClassSize.estimateBase(cl, true);
314      assertEquals(expected, actual);
315    }
316
317    // CachedBlock Fixed Overhead
318    // We really need "deep" sizing but ClassSize does not do this.
319    // Perhaps we should do all these more in this style....
320    cl = LruCachedBlock.class;
321    actual = LruCachedBlock.PER_BLOCK_OVERHEAD;
322    expected = ClassSize.estimateBase(cl, false);
323    expected += ClassSize.estimateBase(String.class, false);
324    expected += ClassSize.estimateBase(ByteBuffer.class, false);
325    if(expected != actual) {
326      ClassSize.estimateBase(cl, true);
327      ClassSize.estimateBase(String.class, true);
328      ClassSize.estimateBase(ByteBuffer.class, true);
329      assertEquals(expected, actual);
330    }
331
332    // DefaultMemStore Overhead
333    cl = DefaultMemStore.class;
334    actual = DefaultMemStore.FIXED_OVERHEAD;
335    expected = ClassSize.estimateBase(cl, false);
336    if(expected != actual) {
337      ClassSize.estimateBase(cl, true);
338      assertEquals(expected, actual);
339    }
340
341    // DefaultMemStore Deep Overhead
342    actual = DefaultMemStore.DEEP_OVERHEAD;
343    expected = ClassSize.estimateBase(cl, false);
344    if (expected != actual) {
345      ClassSize.estimateBase(cl, true);
346      assertEquals(expected, actual);
347    }
348
349    // CompactingMemStore Deep Overhead
350    cl = CompactingMemStore.class;
351    actual = CompactingMemStore.DEEP_OVERHEAD;
352    expected = ClassSize.estimateBase(cl, false);
353    expected += ClassSize.estimateBase(AtomicBoolean.class, false);
354    expected += ClassSize.estimateBase(AtomicBoolean.class, false);
355    expected += ClassSize.estimateBase(CompactionPipeline.class, false);
356    expected += ClassSize.estimateBase(LinkedList.class, false); //inside CompactionPipeline
357    expected += ClassSize.estimateBase(LinkedList.class, false); //inside CompactionPipeline
358    expected += ClassSize.estimateBase(MemStoreCompactor.class, false);
359    expected += ClassSize.estimateBase(AtomicBoolean.class, false);// inside MemStoreCompactor
360    if (expected != actual) {
361      ClassSize.estimateBase(cl, true);
362      ClassSize.estimateBase(AtomicBoolean.class, true);
363      ClassSize.estimateBase(AtomicBoolean.class, true);
364      ClassSize.estimateBase(CompactionPipeline.class, true);
365      ClassSize.estimateBase(LinkedList.class, true);
366      ClassSize.estimateBase(LinkedList.class, true);
367      ClassSize.estimateBase(MemStoreCompactor.class, true);
368      ClassSize.estimateBase(AtomicBoolean.class, true);
369      assertEquals(expected, actual);
370    }
371
372    // Segment Deep overhead
373    cl = Segment.class;
374    actual = Segment.DEEP_OVERHEAD;
375    expected = ClassSize.estimateBase(cl, false);
376    expected += 2 * ClassSize.estimateBase(AtomicLong.class, false);
377    expected += ClassSize.estimateBase(AtomicReference.class, false);
378    expected += ClassSize.estimateBase(CellSet.class, false);
379    expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false);
380    if (expected != actual) {
381      ClassSize.estimateBase(cl, true);
382      ClassSize.estimateBase(AtomicLong.class, true);
383      ClassSize.estimateBase(AtomicReference.class, true);
384      ClassSize.estimateBase(CellSet.class, true);
385      ClassSize.estimateBase(ReentrantReadWriteLock.class,true);
386      assertEquals(expected, actual);
387    }
388
389    // MutableSegment Deep overhead
390    cl = MutableSegment.class;
391    actual = MutableSegment.DEEP_OVERHEAD;
392    expected = ClassSize.estimateBase(cl, false);
393    expected += 2 * ClassSize.estimateBase(AtomicLong.class, false);
394    expected += ClassSize.estimateBase(AtomicReference.class, false);
395    expected += ClassSize.estimateBase(CellSet.class, false);
396    expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false);
397    expected += ClassSize.estimateBase(SyncTimeRangeTracker.class, false);
398    expected += ClassSize.estimateBase(ConcurrentSkipListMap.class, false);
399    expected += ClassSize.estimateBase(AtomicBoolean.class, false);
400    if (expected != actual) {
401      ClassSize.estimateBase(cl, true);
402      ClassSize.estimateBase(AtomicLong.class, true);
403      ClassSize.estimateBase(AtomicLong.class, true);
404      ClassSize.estimateBase(AtomicReference.class, true);
405      ClassSize.estimateBase(CellSet.class, true);
406      ClassSize.estimateBase(ReentrantReadWriteLock.class,true);
407      ClassSize.estimateBase(SyncTimeRangeTracker.class, true);
408      ClassSize.estimateBase(ConcurrentSkipListMap.class, true);
409      ClassSize.estimateBase(AtomicBoolean.class,true);
410      assertEquals(expected, actual);
411    }
412
413    // ImmutableSegments Deep overhead
414    cl = ImmutableSegment.class;
415    actual = ImmutableSegment.DEEP_OVERHEAD;
416    expected = ClassSize.estimateBase(cl, false);
417    expected += 2 * ClassSize.estimateBase(AtomicLong.class, false);
418    expected += ClassSize.estimateBase(AtomicReference.class, false);
419    expected += ClassSize.estimateBase(CellSet.class, false);
420    expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false);
421    expected += ClassSize.estimateBase(NonSyncTimeRangeTracker.class, false);
422    if (expected != actual) {
423      ClassSize.estimateBase(cl, true);
424      ClassSize.estimateBase(AtomicLong.class, true);
425      ClassSize.estimateBase(AtomicLong.class, true);
426      ClassSize.estimateBase(AtomicReference.class, true);
427      ClassSize.estimateBase(CellSet.class, true);
428      ClassSize.estimateBase(ReentrantReadWriteLock.class,true);
429      ClassSize.estimateBase(NonSyncTimeRangeTracker.class, true);
430      assertEquals(expected, actual);
431    }
432
433    cl = CSLMImmutableSegment.class;
434    actual = CSLMImmutableSegment.DEEP_OVERHEAD_CSLM;
435    expected = ClassSize.estimateBase(cl, false);
436    expected += 2 * ClassSize.estimateBase(AtomicLong.class, false);
437    expected += ClassSize.estimateBase(AtomicReference.class, false);
438    expected += ClassSize.estimateBase(CellSet.class, false);
439    expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false);
440    expected += ClassSize.estimateBase(NonSyncTimeRangeTracker.class, false);
441    expected += ClassSize.estimateBase(ConcurrentSkipListMap.class, false);
442    if (expected != actual) {
443      ClassSize.estimateBase(cl, true);
444      ClassSize.estimateBase(AtomicLong.class, true);
445      ClassSize.estimateBase(AtomicLong.class, true);
446      ClassSize.estimateBase(AtomicReference.class, true);
447      ClassSize.estimateBase(CellSet.class, true);
448      ClassSize.estimateBase(ReentrantReadWriteLock.class,true);
449      ClassSize.estimateBase(NonSyncTimeRangeTracker.class, true);
450      ClassSize.estimateBase(ConcurrentSkipListMap.class, true);
451      assertEquals(expected, actual);
452    }
453    cl = CellArrayImmutableSegment.class;
454    actual = CellArrayImmutableSegment.DEEP_OVERHEAD_CAM;
455    expected = ClassSize.estimateBase(cl, false);
456    expected += 2 * ClassSize.estimateBase(AtomicLong.class, false);
457    expected += ClassSize.estimateBase(AtomicReference.class, false);
458    expected += ClassSize.estimateBase(CellSet.class, false);
459    expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false);
460    expected += ClassSize.estimateBase(NonSyncTimeRangeTracker.class, false);
461    expected += ClassSize.estimateBase(CellArrayMap.class, false);
462    if (expected != actual) {
463      ClassSize.estimateBase(cl, true);
464      ClassSize.estimateBase(AtomicLong.class, true);
465      ClassSize.estimateBase(AtomicLong.class, true);
466      ClassSize.estimateBase(AtomicReference.class, true);
467      ClassSize.estimateBase(CellSet.class, true);
468      ClassSize.estimateBase(ReentrantReadWriteLock.class,true);
469      ClassSize.estimateBase(NonSyncTimeRangeTracker.class, true);
470      ClassSize.estimateBase(CellArrayMap.class, true);
471      assertEquals(expected, actual);
472    }
473
474    // Store Overhead
475    cl = HStore.class;
476    actual = HStore.FIXED_OVERHEAD;
477    expected = ClassSize.estimateBase(cl, false);
478    if(expected != actual) {
479      ClassSize.estimateBase(cl, true);
480      assertEquals(expected, actual);
481    }
482
483    // Region Overhead
484    cl = HRegion.class;
485    actual = HRegion.FIXED_OVERHEAD;
486    expected = ClassSize.estimateBase(cl, false);
487    if (expected != actual) {
488      ClassSize.estimateBase(cl, true);
489      assertEquals(expected, actual);
490    }
491
492    cl = StoreHotnessProtector.class;
493    actual = StoreHotnessProtector.FIXED_SIZE;
494    expected = ClassSize.estimateBase(cl, false);
495    if (expected != actual) {
496      ClassSize.estimateBase(cl, true);
497      assertEquals(expected, actual);
498    }
499
500    // Block cache key overhead. Only tests fixed overhead as estimating heap
501    // size of strings is hard.
502    cl = BlockCacheKey.class;
503    actual = BlockCacheKey.FIXED_OVERHEAD;
504    expected  = ClassSize.estimateBase(cl, false);
505    if (expected != actual) {
506      ClassSize.estimateBase(cl, true);
507      assertEquals(expected, actual);
508    }
509
510    // Currently NOT testing Deep Overheads of many of these classes.
511    // Deep overheads cover a vast majority of stuff, but will not be 100%
512    // accurate because it's unclear when we're referencing stuff that's already
513    // accounted for.  But we have satisfied our two core requirements.
514    // Sizing is quite accurate now, and our tests will throw errors if
515    // any of these classes are modified without updating overhead sizes.
516  }
517
518  @Test
519  public void testMutations(){
520    Class<?> cl;
521    long expected;
522    long actual;
523
524    cl = TimeRange.class;
525    actual = ClassSize.TIMERANGE;
526    expected  = ClassSize.estimateBase(cl, false);
527    if (expected != actual) {
528      ClassSize.estimateBase(cl, true);
529      assertEquals(expected, actual);
530    }
531
532    byte[] row = new byte[] { 0 };
533    cl = Put.class;
534    actual = Mutation.MUTATION_OVERHEAD + ClassSize.align(ClassSize.ARRAY);
535    expected = ClassSize.estimateBase(cl, false);
536    //The actual TreeMap is not included in the above calculation
537    expected += ClassSize.align(ClassSize.TREEMAP);
538    expected += ClassSize.align(ClassSize.INTEGER); // priority
539    if (expected != actual) {
540      ClassSize.estimateBase(cl, true);
541      assertEquals(expected, actual);
542    }
543
544    cl = Delete.class;
545    actual = Mutation.MUTATION_OVERHEAD + ClassSize.align(ClassSize.ARRAY);
546    expected  = ClassSize.estimateBase(cl, false);
547    //The actual TreeMap is not included in the above calculation
548    expected += ClassSize.align(ClassSize.TREEMAP);
549    expected += ClassSize.align(ClassSize.INTEGER); // priority
550    if (expected != actual) {
551      ClassSize.estimateBase(cl, true);
552      assertEquals(expected, actual);
553    }
554  }
555
556  @Test
557  public void testReferenceSize() {
558    LOG.info("ClassSize.REFERENCE is " + ClassSize.REFERENCE);
559    // oop should be either 4 or 8
560    assertTrue(ClassSize.REFERENCE == 4 || ClassSize.REFERENCE == 8);
561  }
562
563  @Test
564  public void testObjectSize() throws IOException {
565    LOG.info("header:" + ClassSize.OBJECT);
566    LOG.info("array header:" + ClassSize.ARRAY);
567
568    if (ClassSize.is32BitJVM()) {
569      assertEquals(ClassSize.OBJECT, 8);
570    } else {
571      assertTrue(ClassSize.OBJECT == 12 || ClassSize.OBJECT == 16); // depending on CompressedOops
572    }
573    if (ClassSize.useUnsafeLayout()) {
574      assertEquals(ClassSize.ARRAY, ClassSize.OBJECT + 4);
575    } else {
576      assertEquals(ClassSize.ARRAY, ClassSize.OBJECT + 8);
577    }
578  }
579}
580