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 }