18

I have a Perl script where I maintain a very simple cache using a hash table. I would like to clear the hash once it occupies more than n bytes, to avoid Perl (32-bit) running out of memory and crashing.

I can do a check on the number of keys-value pairs:

if (scalar keys %cache > $maxSize)
 {
 %cache = ();
 }

But is it possible to check the actual memory occupied by the hash?

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Nikhil
  • 2,028
  • 7
  • 24
  • 33

7 Answers7

27

Devel::Size is the answer to your question. (Note that Devel::Size will temporarily allocate a significant amount of memory when processing a large data structure, so it's not really well suited to this purpose.)

However, Cache::SizeAwareMemoryCache and Tie::Cache already implement what you're looking for (with somewhat different interfaces), and could save you from reinventing the wheel.

Memoize is a module that makes it simple to cache the return value from a function. It doesn't implement a size-based cache limit, but it should be possible to use Tie::Cache as a backend for Memoize.

cjm
  • 61,471
  • 9
  • 126
  • 175
11

You're looking for Devel::Size

NAME

Devel::Size - Perl extension for finding the memory usage of Perl variables

SYNOPSIS

use Devel::Size qw(size total_size);

my $size = size("A string");
my @foo = (1, 2, 3, 4, 5);
my $other_size = size(\@foo);
my $foo = {a => [1, 2, 3],
        b => {a => [1, 3, 4]}
       };
my $total_size = total_size($foo);
cjm
  • 61,471
  • 9
  • 126
  • 175
mbac32768
  • 11,453
  • 9
  • 34
  • 40
  • 1
    You should have warned the questioner that using Devel::Size on a large data structure will use a very large amount of memory. – user11318 Sep 20 '08 at 00:40
  • why when using in on scalars as 5, 6 or even 60000000000000000000000000000000000000 I always get the same result? I would expect that above 2^63 -1 scalars take more bytes than just 24, which is the amount that I get @cjm – Iván Rodríguez Torres Mar 02 '17 at 00:14
  • 1
    @IvánRodríguezTorres, unless you're using bignums, large numbers are stored as double-precision floating point values, which are all the same size. – cjm Mar 03 '17 at 21:46
6

You can install Devel::Size to find out the memory taken by any construct in Perl. However do be aware that it will take a large amount of intermediate memory, so I would not use it against a large data structure. I would certainly not do it if you think you may be about to run out of memory.

BTW there are a number of good modules on CPAN to do caching in memory and otherwise. Rather than roll your own I would suggest using one of them instead. For instance try Tie::Cache::LRU for an in-memory cache that will only go up to a specified number of keys.

cjm
  • 61,471
  • 9
  • 126
  • 175
user11318
  • 9,273
  • 2
  • 25
  • 25
2

You can use Devel::Size to determine the memory used, but you can't generally give return memory to the OS. It sounds like you're just trying to clear and reuse, though, which should work fine.

If the cache is for a function, consider using the Memoize module instead of maintaining the cache yourself. It supports cache expiration (via Memoize::Expire) so you can limit the size of the cache without destroying it entirely.

Michael Carman
  • 30,628
  • 10
  • 74
  • 122
1

Cache::Memory

use Cache::Memory;

my $cache = Cache::Memory->new(
  namespace => 'MyNamespace',
  default_expires => '600 sec'
);

my $size  = $cache->size()
my $limit = $cache->size_limit();
Community
  • 1
  • 1
Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
1

If you're worrying about managing the amount of memory that Perl is using, you should probably look at an alternative approach. Why do you need that much in RAM all at once? Should you be using some sort of persistence system?

Andy Lester
  • 91,102
  • 13
  • 100
  • 152
0

As others have said, caching is not a wheel you need to re-invent, there's plenty of simple caching solutions on CPAN which will do the job nicely for you.

Cache::SizeAwareMemoryCache can be told the maximum size you want it to use, then you can leave it to care about the cache for you.

cjm
  • 61,471
  • 9
  • 126
  • 175
David Precious
  • 6,544
  • 1
  • 24
  • 31