The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl

use strict;
use warnings;

use List::UtilsBy qw( max_by );

use Devel::MAT;

my $pmat = Devel::MAT->load( $ARGV[0] // die "Need dumpfile\n" );
$pmat->load_tool( "Sizes" );

my $size = "owned_size";
my $set  = "owned_set";

my %seen;

our $INDENT = "";
sub list_largest_svs
{
   my ( $svlist, @counts ) = @_;

   my $count = shift @counts;
   while( $count-- ) {
      my $largest = max_by { $_->$size } grep { !$seen{$_->addr} } @$svlist;
      defined $largest or last;

      $seen{$largest->addr}++;
      printf "$INDENT%s: %d bytes%s\n",
         $largest->desc_addr,
         $largest->$size,
         ( @counts ? ": of which" : "" );

      my @set = $largest->$set;
      shift @set; # SV itself is always first

      if( @counts ) {
         local $INDENT = "$INDENT    ";
         list_largest_svs( \@set, @counts );
      }

      $seen{$_->addr}++ for @set;
   }

   my $others = 0;
   $others += $_->size for grep { !$seen{$_->addr} } @$svlist;
   printf "${INDENT}others: %d bytes\n", $others if $others;
}

list_largest_svs( [ $pmat->dumpfile->heap ], 5, 3, 2 );