protected void increaseCounter(Runnable task) {
    if (!shouldCount(task)) {
      return;
    }

    Settings settings = this.settings;
    long maxChannelMemorySize = settings.maxChannelMemorySize;

    int increment = settings.objectSizeEstimator.estimateSize(task);

    if (task instanceof ChannelEventRunnable) {
      ChannelEventRunnable eventTask = (ChannelEventRunnable) task;
      eventTask.estimatedSize = increment;
      Channel channel = eventTask.getEvent().getChannel();
      long channelCounter = getChannelCounter(channel).addAndGet(increment);
      // System.out.println("IC: " + channelCounter + ", " + increment);
      if (maxChannelMemorySize != 0 && channelCounter >= maxChannelMemorySize && channel.isOpen()) {
        if (channel.isReadable()) {
          // System.out.println("UNREADABLE");
          ChannelHandlerContext ctx = eventTask.getContext();
          if (ctx.getHandler() instanceof ExecutionHandler) {
            // readSuspended = true;
            ctx.setAttachment(Boolean.TRUE);
          }
          channel.setReadable(false);
        }
      }
    } else {
      ((MemoryAwareRunnable) task).estimatedSize = increment;
    }

    if (totalLimiter != null) {
      totalLimiter.increase(increment);
    }
  }
 /**
  * Returns {@code true} if and only if the specified {@code task} should be counted to limit the
  * global and per-channel memory consumption. To override this method, you must call {@code
  * super.shouldCount()} to make sure important tasks are not counted.
  */
 protected boolean shouldCount(Runnable task) {
   if (task instanceof ChannelEventRunnable) {
     ChannelEventRunnable r = (ChannelEventRunnable) task;
     ChannelEvent e = r.getEvent();
     if (e instanceof WriteCompletionEvent) {
       return false;
     } else if (e instanceof ChannelStateEvent) {
       if (((ChannelStateEvent) e).getState() == ChannelState.INTEREST_OPS) {
         return false;
       }
     }
   }
   return true;
 }
  protected void decreaseCounter(Runnable task) {
    if (!shouldCount(task)) {
      return;
    }

    Settings settings = this.settings;
    long maxChannelMemorySize = settings.maxChannelMemorySize;

    int increment;
    if (task instanceof ChannelEventRunnable) {
      increment = ((ChannelEventRunnable) task).estimatedSize;
    } else {
      increment = ((MemoryAwareRunnable) task).estimatedSize;
    }

    if (totalLimiter != null) {
      totalLimiter.decrease(increment);
    }

    if (task instanceof ChannelEventRunnable) {
      ChannelEventRunnable eventTask = (ChannelEventRunnable) task;
      Channel channel = eventTask.getEvent().getChannel();
      long channelCounter = getChannelCounter(channel).addAndGet(-increment);
      // System.out.println("DC: " + channelCounter + ", " + increment);
      if (maxChannelMemorySize != 0 && channelCounter < maxChannelMemorySize && channel.isOpen()) {
        if (!channel.isReadable()) {
          // System.out.println("READABLE");
          ChannelHandlerContext ctx = eventTask.getContext();
          if (ctx.getHandler() instanceof ExecutionHandler) {
            // check if the attachment was set as this means that we suspend the channel from reads.
            // This only works when
            // this pool is used with ExecutionHandler but I guess thats good enough for us.
            //
            // See #215
            if (ctx.getAttachment() != null) {
              // readSuspended = false;
              ctx.setAttachment(null);
              channel.setReadable(true);
            }
          } else {
            channel.setReadable(true);
          }
        }
      }
    }
  }