View Javadoc

1   /*
2    * JBoss, Home of Professional Open Source
3    *
4    * Copyright 2008, Red Hat Middleware LLC, and individual contributors
5    * by the @author tags. See the COPYRIGHT.txt in the distribution for a
6    * full listing of individual contributors.
7    *
8    * This is free software; you can redistribute it and/or modify it
9    * under the terms of the GNU Lesser General Public License as
10   * published by the Free Software Foundation; either version 2.1 of
11   * the License, or (at your option) any later version.
12   *
13   * This software is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   * Lesser General Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public
19   * License along with this software; if not, write to the Free
20   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
22   */
23  package org.jboss.netty.handler.execution;
24  
25  import java.lang.reflect.Field;
26  import java.lang.reflect.Modifier;
27  import java.nio.ByteBuffer;
28  import java.util.HashSet;
29  import java.util.Set;
30  import java.util.concurrent.ConcurrentHashMap;
31  import java.util.concurrent.ConcurrentMap;
32  
33  import org.jboss.netty.buffer.ChannelBuffer;
34  import org.jboss.netty.channel.MessageEvent;
35  
36  /**
37   * The default {@link ObjectSizeEstimator} implementation for general purpose.
38   *
39   * @author The Netty Project (netty-dev@lists.jboss.org)
40   * @author Trustin Lee (tlee@redhat.com)
41   *
42   * @version $Rev: 231 $, $Date: 2008-09-04 16:24:42 +0900 (Thu, 04 Sep 2008) $
43   *
44   */
45  public class DefaultObjectSizeEstimator implements ObjectSizeEstimator {
46  
47      private final ConcurrentMap<Class<?>, Integer> class2size =
48          new ConcurrentHashMap<Class<?>, Integer>();
49  
50      /**
51       * Creates a new instance.
52       */
53      public DefaultObjectSizeEstimator() {
54          class2size.put(boolean.class, 4); // Probably an integer.
55          class2size.put(byte.class, 1);
56          class2size.put(char.class, 2);
57          class2size.put(int.class, 4);
58          class2size.put(short.class, 2);
59          class2size.put(long.class, 8);
60          class2size.put(float.class, 4);
61          class2size.put(double.class, 8);
62          class2size.put(void.class, 0);
63      }
64  
65      public int estimateSize(Object o) {
66          if (o == null) {
67              return 8;
68          }
69  
70          int answer = 8 + estimateSize(o.getClass(), null);
71  
72          if (o instanceof ChannelEventRunnable) {
73              answer += estimateSize(((ChannelEventRunnable) o).getEvent());
74          } else if (o instanceof MessageEvent) {
75              answer += estimateSize(((MessageEvent) o).getMessage());
76          } else if (o instanceof ChannelBuffer) {
77              answer += ((ChannelBuffer) o).capacity();
78          } else if (o instanceof byte[]) {
79              answer += ((byte[]) o).length;
80          } else if (o instanceof ByteBuffer) {
81              answer += ((ByteBuffer) o).remaining();
82          } else if (o instanceof CharSequence) {
83              answer += ((CharSequence) o).length() << 1;
84          } else if (o instanceof Iterable) {
85              for (Object m : (Iterable<?>) o) {
86                  answer += estimateSize(m);
87              }
88          }
89  
90          return align(answer);
91      }
92  
93      private int estimateSize(Class<?> clazz, Set<Class<?>> visitedClasses) {
94          Integer objectSize = class2size.get(clazz);
95          if (objectSize != null) {
96              return objectSize;
97          }
98  
99          if (visitedClasses != null) {
100             if (visitedClasses.contains(clazz)) {
101                 return 0;
102             }
103         } else {
104             visitedClasses = new HashSet<Class<?>>();
105         }
106 
107         visitedClasses.add(clazz);
108 
109         int answer = 8; // Basic overhead.
110         for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
111             Field[] fields = c.getDeclaredFields();
112             for (Field f : fields) {
113                 if ((f.getModifiers() & Modifier.STATIC) != 0) {
114                     // Ignore static fields.
115                     continue;
116                 }
117 
118                 answer += estimateSize(f.getType(), visitedClasses);
119             }
120         }
121 
122         visitedClasses.remove(clazz);
123 
124         // Some alignment.
125         answer = align(answer);
126 
127         // Put the final answer.
128         class2size.putIfAbsent(clazz, answer);
129         return answer;
130     }
131 
132     private static int align(int size) {
133         if (size % 8 != 0) {
134             size /= 8;
135             size ++;
136             size *= 8;
137         }
138         return size;
139     }
140 }