View Javadoc

1   /***
2    *  Copyright 2003-2010 Terracotta, Inc.
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  package net.sf.ehcache.pool.sizeof;
18  
19  import java.util.concurrent.ConcurrentHashMap;
20  
21  import net.sf.ehcache.pool.sizeof.ObjectGraphWalker.Visitor;
22  import net.sf.ehcache.pool.sizeof.filter.SizeOfFilter;
23  
24  
25  /***
26   * Abstract sizeOf for Java. It will rely on a proper sizeOf to measure sizes of entire object graphs
27   * @author Alex Snaps
28   */
29  public abstract class SizeOf {
30  
31      private final ObjectGraphWalker walker;
32  
33      /***
34       * Builds a new SizeOf that will filter fields according to the provided filter
35       * @param fieldFilter The filter to apply
36       * @param caching whether to cache reflected fields
37       * @see SizeOfFilter
38       */
39      public SizeOf(SizeOfFilter fieldFilter, boolean caching) {
40          ObjectGraphWalker.Visitor visitor;
41          if (caching) {
42              visitor = new CachingSizeOfVisitor();
43          } else {
44              visitor = new SizeOfVisitor();
45          }
46          this.walker = new ObjectGraphWalker(visitor, fieldFilter);
47      }
48  
49      /***
50       * Calculates the size in memory (heap) of the instance passed in, not navigating the down graph
51       *
52       * @param obj the object to measure the size of
53       * @return the object size in memory in bytes
54       */
55      public long sizeOf(Object obj) {
56          if (isSharedFlyweight(obj)) {
57              return 0;
58          } else {
59              return measureSizeOf(obj);
60          }
61      }
62  
63      /***
64       * Measure the size of an instance
65       * @param obj the reference to measure
66       * @return the size occupied on heap in bytes
67       */
68      protected abstract long measureSizeOf(Object obj);
69  
70      /***
71       * Measures the size in memory (heap) of the objects passed in, walking their graph down
72       * Any overlap of the graphs being passed in will be recognized and only measured once
73       *
74       * @param obj the root objects of the graphs to measure
75       * @return the total size in bytes for these objects
76       * @see #sizeOf(Object)
77       */
78      public long deepSizeOf(Object... obj) {
79          return walker.walk(obj);
80      }
81  
82      private static boolean isSharedFlyweight(Object obj) {
83          FlyweightType type = FlyweightType.getFlyweightType(obj.getClass());
84          return type != null && type.isShared(obj);
85      }
86  
87      /***
88       * Will return the sizeOf eahc instance
89       */
90      private class SizeOfVisitor implements Visitor {
91  
92          /***
93           * {@inheritDoc}
94           */
95          public long visit(Object object) {
96              return sizeOf(object);
97          }
98      }
99  
100     /***
101      * Will Cache already visited types
102      */
103     private class CachingSizeOfVisitor implements Visitor {
104         private final ConcurrentHashMap<String, Long> cache = new ConcurrentHashMap<String, Long>();
105 
106         /***
107          * {@inheritDoc}
108          */
109         @Override
110         public long visit(final Object object) {
111             Class<?> klazz = object.getClass();
112             Long cachedSize = cache.get(klazz.getName());
113             if (cachedSize == null) {
114                 if (klazz.isArray()) {
115                     return measureSizeOf(object);
116                 } else if (isSharedFlyweight(object)) {
117                     return 0;
118                 } else {
119                     long size = measureSizeOf(object);
120                     cache.put(klazz.getName(), size);
121                     return size;
122                 }
123             } else {
124                 return cachedSize.longValue();
125             }
126         }
127     }
128 }