src/main/java/org/ehcache/sizeof/ObjectGraphWalker.java
long walk(VisitorListener visitorListener, Object... root) {
        final StringBuilder traversalDebugMessage;
        if (USE_VERBOSE_DEBUG_LOGGING && LOG.isDebugEnabled()) {
            traversalDebugMessage = new StringBuilder();
        } else {
            traversalDebugMessage = null;
        }
        long result = 0;
        Deque<Object> toVisit = new ArrayDeque<>();
        Set<Object> visited = newSetFromMap(new IdentityHashMap<>());

        if (root != null) {
            if (traversalDebugMessage != null) {
                traversalDebugMessage.append("visiting ");
            }
            for (Object object : root) {
                nullSafeAdd(toVisit, object);
                if (traversalDebugMessage != null && object != null) {
                    traversalDebugMessage.append(object.getClass().getName())
                        .append("@").append(System.identityHashCode(object)).append(", ");
                }
            }
            if (traversalDebugMessage != null) {
                traversalDebugMessage.deleteCharAt(traversalDebugMessage.length() - 2).append("\n");
            }
        }

        while (!toVisit.isEmpty()) {

            Object ref = toVisit.pop();

            if (visited.add(ref)) {
                Class<?> refClass = ref.getClass();
                if (!byPassIfFlyweight(ref) && shouldWalkClass(refClass)) {
                    if (refClass.isArray() && !refClass.getComponentType().isPrimitive()) {
                        for (int i = 0; i < Array.getLength(ref); i++) {
                            nullSafeAdd(toVisit, Array.get(ref, i));
                        }
                    } else {
                        for (Field field : getFilteredFields(refClass)) {
                            try {
                                nullSafeAdd(toVisit, field.get(ref));
                            } catch (IllegalAccessException ex) {
                                throw new RuntimeException(ex);
                            }
                        }
                    }

                    final long visitSize = visitor.visit(ref);
                    if (visitorListener != null) {
                        visitorListener.visited(ref, visitSize);
                    }
                    if (traversalDebugMessage != null) {
                        traversalDebugMessage.append("  ").append(visitSize).append("b\t\t")
                            .append(ref.getClass().getName()).append("@").append(System.identityHashCode(ref)).append("\n");
                    }
                    result += visitSize;
                } else if (traversalDebugMessage != null) {
                    traversalDebugMessage.append("  ignored\t")
                        .append(ref.getClass().getName()).append("@").append(System.identityHashCode(ref)).append("\n");
                }
            }
        }

        if (traversalDebugMessage != null) {
            traversalDebugMessage.append("Total size: ").append(result).append(" bytes\n");
            LOG.debug(traversalDebugMessage.toString());
        }
        return result;
    }
long walk(VisitorListener visitorListener, Object... root) {
        final StringBuilder traversalDebugMessage;
        if (USE_VERBOSE_DEBUG_LOGGING && LOG.isDebugEnabled()) {
            traversalDebugMessage = new StringBuilder();
        } else {
            traversalDebugMessage = null;
        }
        long result = 0;
        Deque<Object> toVisit = new ArrayDeque<>();
        Set<Object> visited = newSetFromMap(new IdentityHashMap<>());

        if (root != null) {
            if (traversalDebugMessage != null) {
                traversalDebugMessage.append("visiting ");
            }
            for (Object object : root) {
                nullSafeAdd(toVisit, object);
                if (traversalDebugMessage != null && object != null) {
                    traversalDebugMessage.append(object.getClass().getName())
                        .append("@").append(System.identityHashCode(object)).append(", ");
                }
            }
            if (traversalDebugMessage != null) {
                traversalDebugMessage.deleteCharAt(traversalDebugMessage.length() - 2).append("\n");
            }
        }

        while (!toVisit.isEmpty()) {

            Object ref = toVisit.pop();

            if (visited.add(ref)) {
                Class<?> refClass = ref.getClass();
                if (!byPassIfFlyweight(ref) && shouldWalkClass(refClass)) {
                    if (refClass.isArray() && !refClass.getComponentType().isPrimitive()) {
                        for (int i = 0; i < Array.getLength(ref); i++) {
                            nullSafeAdd(toVisit, Array.get(ref, i));
                        }
                    } else {
                        for (Field field : getFilteredFields(refClass)) {
                            try {
                                nullSafeAdd(toVisit, field.get(ref));
                            } catch (IllegalAccessException ex) {
                                throw new RuntimeException(ex);
                            }
                        }
                    }

                    final long visitSize = visitor.visit(ref);
                    if (visitorListener != null) {
                        visitorListener.visited(ref, visitSize);
                    }
                    if (traversalDebugMessage != null) {
                        traversalDebugMessage.append("  ").append(visitSize).append("b\t\t")
                            .append(ref.getClass().getName()).append("@").append(System.identityHashCode(ref)).append("\n");
                    }
                    result += visitSize;
                } else if (traversalDebugMessage != null) {
                    traversalDebugMessage.append("  ignored\t")
                        .append(ref.getClass().getName()).append("@").append(System.identityHashCode(ref)).append("\n");
                }
            }
        }

        if (traversalDebugMessage != null) {
            traversalDebugMessage.append("Total size: ").append(result).append(" bytes\n");
            LOG.debug(traversalDebugMessage.toString());
        }
        return result;
    }
Walk the graph and call into the "visitor"

@param visitorListener          A decorator for the Visitor
@param root                      the roots of the objects (a shared graph will only be visited once)
@return the sum of all Visitor#visit returned values