View Javadoc

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
    10   *    http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *  Unless required by applicable law or agreed to in writing,
    13   *  software distributed under the License is distributed on an
    14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   *  KIND, either express or implied.  See the License for the
    16   *  specific language governing permissions and limitations
    17   *  under the License.
    18   *
    19   */
    20  package org.apache.mina.filter.executor;
    21
    22  import java.lang.reflect.Field;
    23  import java.lang.reflect.Modifier;
    24  import java.util.HashSet;
    25  import java.util.Set;
    26  import java.util.concurrent.ConcurrentHashMap;
    27  import java.util.concurrent.ConcurrentMap;
    28
    29  import org.apache.mina.core.buffer.IoBuffer;
    30  import org.apache.mina.core.session.IoEvent;
    31  import org.apache.mina.core.write.WriteRequest;
    32
    33  /**
    34   * A default {@link IoEventSizeEstimator} implementation.
    35   * <p>
    36   * <a href="http://martin.nobilitas.com/java/sizeof.html">Martin's Java Notes</a>
    37   * was used for estimation.  For unknown types, it inspects declaring fields of the
    38   * class of the specified event and the parameter of the event.  The size of unknown
    39   * declaring fields are approximated to the specified <tt>averageSizePerField</tt>
    40   * (default: 64).
    41   * <p>
    42   * All the estimated sizes of classes are cached for performance improvement.
    43   *
    44   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    45   */
    46  public class DefaultIoEventSizeEstimator implements IoEventSizeEstimator {
    47      /** A map containing the estimated size of each Java objects we know for */
    48      private final ConcurrentMap<Class<?>, Integer> class2size = new ConcurrentHashMap<Class<?>, Integer>();
    49
    50      /**
    51       * Create a new instance of this class, injecting the known size of
    52       * basic java types.
    53       */
    54      public DefaultIoEventSizeEstimator() {
    55          class2size.put(boolean.class, 4); // Probably an integer.
    56          class2size.put(byte.class, 1);
    57          class2size.put(char.class, 2);
    58          class2size.put(int.class, 4);
    59          class2size.put(short.class, 2);
    60          class2size.put(long.class, 8);
    61          class2size.put(float.class, 4);
    62          class2size.put(double.class, 8);
    63          class2size.put(void.class, 0);
    64      }
    65
    66      /**
    67       * {@inheritDoc}
    68       */
    69      public int estimateSize(IoEvent event) {
    70          return estimateSize((Object) event) + estimateSize(event.getParameter());
    71      }
    72
    73      /**
    74       * Estimate the size of an Objecr in number of bytes
    75       * @param message The object to estimate
    76       * @return The estimated size of the object
    77       */
    78      public int estimateSize(Object message) {
    79          if (message == null) {
    80              return 8;
    81          }
    82
    83          int answer = 8 + estimateSize(message.getClass(), null);
    84
    85          if (message instanceof IoBuffer) {
    86              answer += ((IoBuffer) message).remaining();
    87          } else if (message instanceof WriteRequest) {
    88              answer += estimateSize(((WriteRequest) message).getMessage());
    89          } else if (message instanceof CharSequence) {
    90              answer += ((CharSequence) message).length() << 1;
    91          } else if (message instanceof Iterable) {
    92              for (Object m : (Iterable<?>) message) {
    93                  answer += estimateSize(m);
    94              }
    95          }
    96
    97          return align(answer);
    98      }
    99
    100     private int estimateSize(Class<?> clazz, Set<Class<?>> visitedClasses) {
    101         Integer objectSize = class2size.get(clazz);
    102         if (objectSize != null) {
    103             return objectSize;
    104         }
    105
    106         if (visitedClasses != null) {
    107             if (visitedClasses.contains(clazz)) {
    108                 return 0;
    109             }
    110         } else {
    111             visitedClasses = new HashSet<Class<?>>();
    112         }
    113
    114         visitedClasses.add(clazz);
    115
    116         int answer = 8; // Basic overhead.
    117         for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
    118             Field[] fields = c.getDeclaredFields();
    119             for (Field f : fields) {
    120                 if ((f.getModifiers() & Modifier.STATIC) != 0) {
    121                     // Ignore static fields.
    122                     continue;
    123                 }
    124
    125                 answer += estimateSize(f.getType(), visitedClasses);
    126             }
    127         }
    128
    129         visitedClasses.remove(clazz);
    130
    131         // Some alignment.
    132         answer = align(answer);
    133
    134         // Put the final answer.
    135         Integer tmpAnswer = class2size.putIfAbsent(clazz, answer);
    136
    137         if (tmpAnswer != null) {
    138             answer = tmpAnswer;
    139         }
    140
    141         return answer;
    142     }
    143
    144     private static int align(int size) {
    145         if (size % 8 != 0) {
    146             size /= 8;
    147             size++;
    148             size *= 8;
    149         }
    150         return size;
    151     }
    152 }