I am creating an application that needs to make fft on audio data. For the process part, the audio data need to be cast to double. So I wrote this function:

public void processRecordedData<PlatformRecordFormat> (PlatformRecordFormat[] platformRecordedData)
     Array.Copy(platformRecordedData, recordedData, MICROPHONE_SETUP.SAMPLE_COUNT);
    //Processing audio

And this function is called from Xamarin.Android with a short[] as input:

private void processAudioData()
        ProcessAudioDataEvent.WaitOne();
        pianoTrainingPageInstance.processRecordedData(audioBuffers[processIndex]);
        processIndex = (processIndex + 1) % AUDIO_BUFFER_COUNT;
    } while (audioRecord != null);

recordedData and audioBuffers[processIndex] are both created and with the same size.

The problem is that I have a lot of messages from the garbage collector that never stop popping on the application output windows:

[Mono] GC_TAR_BRIDGE bridges 0 objects 0 opaque 0 colors 0 colors-bridged 0 colors-visible 7 xref 0 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.04ms tarjan 0.01ms scc-setup 0.04ms gather-xref 0.00ms xref-setup 0.00ms cleanup 0.00ms
[Mono] GC_BRIDGE: Complete, was running for 0.07ms
[Mono] GC_MINOR: (Nursery full) time 1.17ms, stw 1.92ms promoted 0K major size: 1408K in use: 665K los size: 1024K in use: 654K

It's always those 3 lines. I tried to switch my function from template parameter to short[], I tried copying with a for loop, but there are always those 3 messages.

From what I understand, copying the short array to the double performs memory allocation and because this function is called often, the application goes soon out of memory and the GC have much memory to free. But I don't understand why? Maybe for each element of the short array, a double is created with new and then returned with the converted value? In this case, is there a way to perform a copy without allocating memory? I am from a c++ background so maybe I am doing something wrong by trying yo mimic what I would do in c++.

When I comment the Array.Copy line, the messages disappear.

The messages appear wether I am on real hardware or in the emulator, but with the emulator, I have this in addition :

[zygote64] Background concurrent copying GC freed 1330(2MB) AllocSpace objects, 0(0B) LOS objects, 50% free, 1496KB/2MB, paused 8.911ms total 32.277ms

(It might be unrelated because I have this kind of message from the emultor whether or not I comment the Array.Copy line)

Hi, AdrienCOURNAND-4537. The copying operation may take much memory, try to call GC.Collect() manaually after copying the array.

public void processRecordedData<PlatformRecordFormat> (PlatformRecordFormat[] platformRecordedData)
      Array.Copy(platformRecordedData, recordedData, MICROPHONE_SETUP.SAMPLE_COUNT);
      GC.Collect(0);
     //Processing audio

If it doesn't work, try using Array.Clone method to copy the data.

Hi @JarvanZhang , thanks for the answer. I tried what you ask but the messages still happen.

There is 2 cases: when I use GC.Collect() as you suggested. In this case, nothing changed. When GC.Collect() is called I have the messages displayed. And when I quit the view that performs the copy, then the messages are displayed repeatedly.

When I use Array.Clone(), nothing is displayed when I am to the view that performs the copy, but again, when I change the view the messages are displayed repeatedly.

   SELECTING_LEVEL_VIEW --->     TRAINING_VIEW        ---> SELECTING_LEVEL_VIEW  
     (no [mono] GC msg)         - GC.Collect() : msg       a lot of GC msg  
                                - Array.Clone(): no msg  

I don't get how just doing a for loop allocate memory. Can't I just use the preallocated buffer ?

nothing is displayed when I am to the view that performs the copy, but again, when I change the view the messages are displayed repeatedl

Try to call GC.Collect() command after executing the Array.Clone() method.

It worked, but I have many call to the garbage collector, this is not good for 2 reasons :

  • I need to do realtime audio processing and this will use time
  • This consumes a lot of CPU resources and will drain the battery, I need to be as energy-efficient as possible
  • There is no way to do a copy without allocating memory? Just copying values from a place to another? (I suppose there is)

    Hi, Array.Copy method may require the contiguous memory. Try using ‘for’ to copy the data in a loop.

    And will the code work fine in a console project instead of Xamarin.Android?

    short[] recorded = new short[4096]; double[] audio = new double[4096]; System.Random r = new System.Random((int)new System.DateTime().ToBinary()); while (true) for (int i = 0; i < 4096; i++) recorded[i] = (short)r.Next(); Array.Copy(recorded, audio, 4096); GC.Collect(0);

    and it worked fine. So maybe, it's android that allocates memory in the AudioRecord.Read function (but I doubt). Whether I use a for loop or Array.Copy makes no differences in the app code, I always GC messages