Beads is using too much memory

hello,

I am using the Beads library to play many sound files, sometimes simultaneously.
As new files get periodically loaded and played I want the old ones to stop and be unloaded.
But even when I explicitly ask Beads’ SampleManager to remove samples it seems the memory used by the sketch is gradually increasing and never goes back down.
I have tried other methods such as replacing samples in existing SamplePlayer objects rather than creating new objects or forcing garbage collection but nothing seems to help.
The main page of Beads also mentions an existing method to use buffers rather than loading whole samples in memory which might be worth trying but I can’t find anything else about it in the javadoc.
Is there something I’m missing ?

here is a simplified version of my current code :


import beads.*;
import java.util.Arrays; 

ArrayList<String> filesToPlay = new ArrayList<String>();
ArrayList<Player> players = new ArrayList<Player>();

AudioContext ac;
Gain gain = new Gain(2, 0.5);

void setup() {
  size(300, 300);
  frameRate(30);
  ac = AudioContext.getDefaultContext();
  ac.out.addInput(gain);
  ac.start();
  String[] files = getAllFilesFrom("D:/path/to a folder/containing/a lot of/sound files");
  for (String f : files) filesToPlay.add(f);
}

void draw() {
}

void keyPressed() {
  playSomething();
}

void playSomething() {
  if (filesToPlay.size()>0) players.add(new Player());
  if (players.size()>2) players.get(0).kill();
}

class Player {
  SamplePlayer samplePlayer;
  Panner panner;
  String url;

  Player() {
    try {
      url = filesToPlay.remove(floor(random(filesToPlay.size())));
      samplePlayer = new SamplePlayer(SampleManager.sample(url));
      panner = new Panner(ac, 0);
      panner.setPos(0);
      panner.addInput(samplePlayer);
      samplePlayer.setKillOnEnd(true);
      panner.addInput(samplePlayer);
      gain.addInput(panner);
      samplePlayer.start();
    }
    catch(Exception e) {
      println(e);
    }
  }

  void kill() {
    try {
      samplePlayer.pause(true);
      if (samplePlayer.getSample()!=null) {
        SampleManager.removeSample(samplePlayer.getSample());
        samplePlayer.getSample().clear();
      }
      gain.removeAllConnections(panner);
      panner.removeAllConnections(samplePlayer);
      panner.kill();
      samplePlayer.kill();
    }
    catch(Exception e) {
      println(e);
    }
    players.remove(this);
  }
}

String[] getAllFilesFrom(String folderUrl) {
  File folder = new File(folderUrl);
  File[] filesPath = folder.listFiles();
  String[] result = new String[filesPath.length];
  for (int i=0; i<filesPath.length; i++) {
    result[i]=filesPath[i].toString();
  }
  return result;
}

Alternatively I could switch to another sound library if needed.

I have tried the built-in Sound library of Processing but encountered the same memory problem.

I have tried Minim and it was better regarding memory but it still gets saturated eventually.

Also I choose Beads over those two others because there was some playback options (such as panning, playing in reverse, pitch manipulation, visualization etc) that were possible and more formats handled.

I have no clue but out of curiosity, how big are the sound files and how many files do you have?

What I understand is that Java has sometimes issues with “garbage collection” of the memory - so I’m not surprised that the memory is not freed properly. And how do you check the memory usage? The system “activity monitor” is often misleading as memory can still show up as being used while already freed.

Also you can change the max memory usage from Processing IDE’s preferences (if that is capping the usage).

hello and thanks for your answer,
the files can vary in size but are generally between 1 and 5 Mb.
I check the memory usage on windows task manager, it is going up and down but more up than down, I don’t know how accurate it is but once it reaches 3Gb or so it makes the whole system slow down and crash so it’s probably not just a misleading info.
I don’t know how to “monitor” the garbage collection, yes I suspect something is wrong there.
The max memory usage is already at 4096Mb, even if I could increase it that would just delay the crash and not prevent it.

So can I assume that you have thousands of those files? If you definitely need to use Processing, I would try eclipse or intellij to run the code and use their memory analyzer to see what is actually eating the ram (which may be, I know, not easy to spot).

I don’t know your use case but I would also consider using openFrameworks because c++ can be more straightforward when it comes to memory management - you can always use OSC for communication between programs.

I have thousands of files yes but I only play a maximum of five of them at the same time, I regularly replace one with another.

I’m used to processing so it was easier for me but I could try something else, also I had never heard of Intellij and I’ll have a look at it, thanks for the recommendation.

This has nothing to do with Java or garbage collection. Something is keeping the sample reference alive. You might want to check this message on the Beads list https://groups.google.com/g/beadsproject/c/n_IpTbD8FMA Or ask there.

1 Like

This specific post is about adding a kill listener to kill UGens, but since I’m already calling kill() and removeSample() on every samples and UGens involved when I don’t need them I don’t think an additional kill trigger would help.
But thanks for mentioning this group, I read other posts on it about memory issues and as far as I can understand mine seems to be due to another library used by beads to decode MP3 files that wouldn’t free its memory properly.
As a test I’m trying to run my code using only files that are not mp3 and there is no memory problem anymore so that confirms it (but ideally I’d like to handle mp3 as well).

1 Like

Yes, remembered that post, but wasn’t sure if it was an exact overlap. Definitely worth posting there though, as never seen Ollie posting here.

It sounds like either Beads or underlying MP3 support is not correctly releasing a resource. You could also try VisualVM, trigger a heap dump, search for relevant types. Right-clicking on an instance and using Show GC Root, will tell you what is holding the reference. Useful tool, but takes a bit of reading up.

Also, using Wav over MP3 might actually be a good choice here anyway.

1 Like

thanks a lot, I’ll investigate all this and probably post a message over there at some point