colgreen / sharpneat

SharpNEAT - Evolution of Neural Networks. A C# .NET Framework.
https://sharpneat.sourceforge.io/
Other
380 stars 97 forks source link

Memory leak #20

Closed Pulsar79 closed 6 years ago

Pulsar79 commented 6 years ago

Hello.

First of all, congratulations on the great library you're making. I am using this library to find a network that makes me the best regression with a series of training data and then with other data valid network setting. The problem is that I need to create many new networks NEAT and as I create I'm going up the memory and does not release. Visual Studio tells me that is the structure "KeyedCircularBuffer" but I do not see that there is a "dispose ". Can you help me?. Thank you.

colgreen commented 6 years ago

Sounds like you're creating multiple instances of the main evolution algorithm class, running it and keeping a reference to the champion genome. In turn that will 'keep-alive' all the objects being pointed two (in the tree/network of object references in .NET).

That's my best guess at what's going on from what you've said. Does that sound about right?

Pulsar79 commented 6 years ago

When I finish using a new instance of "NeatEvolutionAlgorithm (of SharpNeat genomes. Neat NeatGenome) ", I do "dispose " and " = null ", as well as:

Private _genomeFactory As IGenomeFactory(Of SharpNeat.Genomes.Neat.NeatGenome) Private _genomeList As List(Of SharpNeat.Genomes.Neat.NeatGenome) Private _ea As NeatEvolutionAlgorithm(Of SharpNeat.Genomes.Neat.NeatGenome) Private _experiment As NeatExperiment2 = Nothing

Protected Overridable Sub Dispose(disposing As Boolean) If Not disposedValue Then

        If disposing Then

            ' Elimine el estado administrado (objetos administrados).
            If Not Me._bestGenormeForm Is Nothing Then
                Me._bestGenormeForm.Dispose()
                Me._bestGenormeForm = Nothing
            End If

            If Not Me._evaluadorRedEntrenamiento Is Nothing Then
                Me._evaluadorRedEntrenamiento.Dispose()
                Me._evaluadorRedEntrenamiento = Nothing
            End If

            If Not Me._evaluadorRedValidacion Is Nothing Then
                Me._evaluadorRedValidacion.Dispose()
                Me._evaluadorRedValidacion = Nothing
            End If

            If Not Me._experiment Is Nothing Then
                Me._experiment.Dispose()
                Me._experiment = Nothing
            End If

            If Not Me._genomeFactory Is Nothing Then
                Me._genomeFactory.Dispose()
                Me._genomeFactory = Nothing
            End If

            If Not Me._genomeList Is Nothing Then
                For i As Integer = 0 To Me._genomeList.Count - 1

                    Me._genomeList(i).Dispose()
                    Me._genomeList(i) = Nothing

                Next

                Me._genomeList.Clear()
                Me._genomeList = Nothing
            End If

            Me._normalizador = Nothing
            Me._obrasEntrenamiento = Nothing
            Me._obrasValidacion = Nothing

            If Not Me._ea Is Nothing Then
                Me._ea.Dispose()
                Me._ea = Nothing
            End If

        End If

        ' TODO: libere los recursos no administrados (objetos no administrados) y reemplace Finalize() a continuación.
        ' TODO: configure los campos grandes en nulos.
    End If
    disposedValue = True
End Sub
Pulsar79 commented 6 years ago

I have write the "Dispose" methods in your library:

NeatGenomeFactory: public void Dispose() { // Eliminamos todo lo que tenga esta clase if (this._addedConnectionBuffer != null) { this._addedConnectionBuffer.Clear(); this._addedConnectionBuffer = null; }

        if (this._addedNeuronBuffer != null)
        {
            this._addedNeuronBuffer.Clear();
            this._addedNeuronBuffer = null;
        }

    }

NeatGenome: public void Dispose() { // Eliminamos todo lo que tenga esta clase if (this._connectionGeneList != null) { this._connectionGeneList.Clear(); this._connectionGeneList = null; }

        if (this._genomeFactory != null)
        {
            this._genomeFactory.Dispose();
            this._genomeFactory = null;
        }

        if (this._neuronGeneList != null)
        {
            this._neuronGeneList.Clear();
            this._neuronGeneList = null;
        }

    }
colgreen commented 6 years ago

OK. By setting null references you are allowing the garbage collector to recover the memory used by those referenced objects. However, you must still have a reference to an object that is preventing the garbage collector from recovering the memory you, e.g. are you keeping a reference to a NeatGenome so that you can use it later? And then running a new NeatEvolutionAlgorithm to find another NeatGenome, etc.

If so then the other solution would be to set neatGenome._genomeFactory to null, which breaks the chain of references that are keeping the GC from collecting the memory. But really I think you should not hold a reference to a NeatGenome, instead you can decode it to a neural net object, and keep a reference to that instead.

But your solution is good too and obviously works for you.

I will leave this issue open as a reminder to implement Dispose() in a few key places in the updated code base currently being worked on offline.

Pulsar79 commented 6 years ago

I know what's going on!

As simple as that, when I called to "Stop " and then "Dispose ", the thread was never finished and remained memory, staying with all the instances and increasing the memory more and more. Now simply, I call "dispose " directly.

Maybe you could take a look to see if you can make that if you call "Dispose " the thread always stop, regardless of whether it is running or paused.

Good thing, what a joy!

1

Pulsar79 commented 6 years ago

I think this line would be missing too:

2

colgreen commented 6 years ago

I will leave this issue open as a reminder to implement Dispose() in a few key places in the updated code base currently being worked on offline.

Closing this now as it's acting as a reminder for a general code quality check/rule.