Returns the approximate total memory footprint an object.

def total_size(obj):
  """Returns the approximate total memory footprint an object."""
  seen = set()
  def sizeof(current_obj):
    try:
      return _sizeof(current_obj)
    except Exception:  # pylint: disable=broad-except
      # Not sure what just happened, but let's assume it's a reference.
      return struct.calcsize('P')

  def _sizeof(current_obj):
    """Do a depth-first acyclic traversal of all reachable objects."""
    if id(current_obj) in seen:
      # A rough approximation of the size cost of an additional reference.
      return struct.calcsize('P')
    seen.add(id(current_obj))
    size = sys.getsizeof(current_obj)

    if isinstance(current_obj, dict):
      size += sum(map(sizeof, itertools.chain.from_iterable(
          six.iteritems(current_obj))))
    elif (isinstance(current_obj, collections.Iterable) and
          not isinstance(current_obj, six.string_types)):
      size += sum(sizeof(item) for item in current_obj)
    elif isinstance(current_obj, records.RecordClass):
      size += sum(sizeof(getattr(current_obj, attr))
                  for attr in current_obj.__slots__)
    return size

  return sizeof(obj)