diff --git a/base/show.jl b/base/show.jl
index 9cd25aba2af9c..5a659baccdf7e 100644
--- a/base/show.jl
+++ b/base/show.jl
@@ -1141,10 +1141,20 @@ function show_nd(io::IO, a::AbstractArray, limit, print_matrix, label_slices)
 end
 
 function whos(m::Module, pattern::Regex)
+    ptr_cache = Set()
     for v in sort(names(m))
         s = string(v)
         if isdefined(m,v) && ismatch(pattern, s)
-            println(rpad(s, 30), summary(eval(m,v)))
+            tsz = ""
+            # totalsizeof might throw, whenever sizeof would throw
+            try
+                bytes = totalsizeof(getfield(m, v), ptr_cache)
+                bytes, mb = prettyprint_getunits(bytes, length(_mem_units), 1024)
+                tsz = string(lpad(bytes, 10), " ", rpad(_mem_units[mb], 6))
+            catch
+                tsz = "undefined"
+            end
+            println(rpad(s, 30), rpad(tsz, 17), summary(eval(m,v)))
         end
     end
 end
diff --git a/base/tuple.jl b/base/tuple.jl
index e77abd8e328d9..c1235a7992485 100644
--- a/base/tuple.jl
+++ b/base/tuple.jl
@@ -15,6 +15,7 @@ getindex(t::Tuple, b::AbstractArray{Bool}) = getindex(t,find(b))
 start(t::Tuple) = 1
 done(t::Tuple, i::Int) = (length(t) < i)
 next(t::Tuple, i::Int) = (t[i], i+1)
+eachindex(t::Tuple) = 1:length(t)
 
 # this allows partial evaluation of bounded sequences of next() calls on tuples,
 # while reducing to plain next() for arbitrary iterables.
diff --git a/base/util.jl b/base/util.jl
index 23a4e7f2ee870..d4d35eced9e31 100644
--- a/base/util.jl
+++ b/base/util.jl
@@ -220,6 +220,44 @@ macro allocated(ex)
     end
 end
 
+# The sum of bytes that the given type references, including
+# itself. The pointer cache (ptr_cache) can be provided. Pointers
+# that are found in the cache do not count towards the sum. The
+# cache must be a ``Set`` like object.
+function totalsizeof(x, ptr_cache = Set())
+    if in(pointer_from_objref(x), ptr_cache)
+        return 0
+    end
+    push!(ptr_cache, pointer_from_objref(x))
+
+    if isa(x, DataType) || isa(x, Symbol)
+        return 0
+    end
+
+    sz = sizeof(x)
+
+    for fn in fieldnames(x)
+        if isdefined(x, fn)
+            el = getfield(x, fn)
+            if !isbits(typeof(el))
+                sz += totalsizeof(el, ptr_cache)
+            end
+        end
+    end
+
+    if isa(x, AbstractArray) || isa(x, Tuple)
+        for idx in eachindex(x)
+            if isdefined(x, idx)
+                el = x[idx]
+                if !isbits(typeof(el))
+                    sz += totalsizeof(el, ptr_cache)
+                end
+            end
+        end
+    end
+    return sz
+end
+
 # print nothing, return value, elapsed time, bytes allocated & gc time
 macro timed(ex)
     quote
diff --git a/test/misc.jl b/test/misc.jl
index 04b9ea07e3515..7fddb5626201c 100644
--- a/test/misc.jl
+++ b/test/misc.jl
@@ -167,3 +167,30 @@ v11801, t11801 = @timed sin(1)
 @test isa(t11801,Real) && t11801 >= 0
 
 @test names(current_module(), true) == names_before_timing
+
+# totalsizeof
+@test Base.totalsizeof(Nothing) == 0
+@test Base.totalsizeof(10) == sizeof(10)
+@test Base.totalsizeof(:mysymbol) >= 0
+@test Base.totalsizeof(Int) >= 0
+@test Base.totalsizeof(Base) >= 0
+@test Base.totalsizeof("123") >= 3
+@test Base.totalsizeof(sizeof) > 0
+@test Base.totalsizeof(rand) > 0
+@test Base.totalsizeof((1, 2, 3, 4)) >= 4*sizeof(Int)
+@test Base.totalsizeof((1.0, 2.0, 3.0, 4.0)) >= 4*sizeof(typeof(1.0))
+@test Base.totalsizeof(Dict{Any, Any}("test1"=>2, "test2"=>3)) >= (8 + 2*sizeof(Int))
+@test Base.totalsizeof(Dict{String, Int}("test1"=>2, "test2"=>3)) >= (8 + 2*sizeof(Int))
+@test Base.totalsizeof([1 2 3]) >= sizeof([1 2 3])
+let
+    x = [1, 2, 3, 4]
+    y = (x, x, x, x, x, x)
+    ptr_cache = Set()
+    @test Base.totalsizeof(y, ptr_cache) < (Base.totalsizeof(x) * length(y))
+end
+let
+    x = "some-string"
+    y = (x, x, x, x, x, x)
+    ptr_cache = Set()
+    @test Base.totalsizeof(y, ptr_cache) < (Base.totalsizeof(x) * length(y))
+end
diff --git a/test/tuple.jl b/test/tuple.jl
index f2e1bc4dee939..e82862a28a5de 100644
--- a/test/tuple.jl
+++ b/test/tuple.jl
@@ -49,6 +49,8 @@
 @test_throws BoundsError next((5,6,7), 0)
 @test_throws BoundsError next((), 1)
 
+@test (5,6,7)[eachindex((5,6,7))] === (5,6,7)
+@test isempty(eachindex(()))
 
 
 ## eltype ##