Should FlacReader::readSamples() allocate memory which isn't cleaned up after completion?


#1

Hi JUCErs,

I have been searching for a way to lower the memory used by my plugin (sampler with 3520 FLAC AudioFormatReaders in memory) and I started looking at the implementation of the FLAC reader.

I found a reservoir buffer which on my machine always gets set to 8096 samples (*2 channels) and I’ve asked if this is somehow controllable, here.

There is no answer on that question, yet, but I realised this only amounts to 1/3 of the extra memory I wasn’t sure about (everything else - preloads etc. is accounted for). So I profiled the initialisation of my plugin and discovered that virtually all that extra memory I couldn’t explain before was allocated in:

juce::FlacReader::readSamples(...)
    FLAC_stream_decoder_process_single
        juce::FlacNamespace::read_frame_(...)
            juce::FlacNamespace::allocate_output_(...)

This memory doesn’t get cleaned up after juce::FlacReader::readSamples() is completed and after a certain point I think it stops growing (probably when each and every reader has read samples from disk).

The problem - with 3520 readers and preload of 4000 samples for each file, I get

 ~107 MB (preload)
+ 214 MB (the memory allocated in readSamples)
+ 214 MB (reservoir buffers)
+ ~50 MB (FLAC_stream_decoder_new and FLAC_stream_decoder_init_stream)
=============================================================
Total: 585 MB

Or otherwise said - the actual preload (which should be the big chunk of data I want to have in memory at all time) clocks at just 18% of the memory used…

Is this how the FLAC reader is supposed to work?
If it does such heavy allocation, I wouldn’t think it will be better creating new readers all the time, right?
And since it has a reservoir of samples, does switching context (file it points to) work safely?


#2

AFAIK there aren’t any leaks in the FLAC code. (We’d have noticed if there was)

If that’s where you’re seeing a leak, then most likely it’s your code that’s leaking the FLAC reader object which owns this memory.


#3

Thanks for responding, @jules.

So, this is the way the reader should work? Occupying ~140 KB of memory per reader?

What do you think I should do:

  • use a pool of readers and reset context (file to read from);
  • or create new readers on the fly (file reading is done in a separate pool of threads, not on the Audio Thread, btw).

Cheers.


#4

Depends entirely on the behaviour you need, but certainly you don’t want there to be any readers hanging around waiting. Maybe cache the start samples from each file so that when you play a new one you can begin playing while you create a reader for it?


#5

That’s what I mean by preload, I am already doing this. OK I’ll try creating the readers on the fly and if it doesn’t work I’ll try the pool idea.

Thanks.