17 messaggi dal 30 marzo 2017
salve a tutti
nel mio piccolo mondo di programmatore vb2019, proveniente da vb2015 e ancora prima da vb6, sto incappando in un problema che sembra non trovare soluzione nonostante abbia girato in lungo ed in largo la rete.
Ho notato che quando si usano i task ed i thread (questi ultimi diciamo ormai vetusti in favore dei primi) la memoria disponibile tende sempre ad aumentare piano piano fino al punto che il programma si blocca per overflow.
Premetto che non sono un mega esperto e programmo per diletto.
Ho creato un software per gestione pannelli solari; deve fare molte cose separatamente (info dall'inverter - invio dati a device iot - invio dati a cloud etc) e per far questo ho usato i threads.
ho notato che il programma si bloccava, anche dopo giorni, per mancanza di memoria.
Dopo avere letto a destra e manca, senza però trovare una risposta risolutiva, mi permetto di chiedere in modo diretto qui, per capire dove e se sbaglio qualcosa.
A dire il vero ho provato anche ad usare i task, ma il problema è rimasto.
Posto qui, a tal proposito, un mini programma che simula quello che devo fare e se lo si manda in esecuzione si vedrà che già dopo 20 minuti la memoria di partenza è di gran lunga inferiore a quella letta al momento.
Mi chiedo : come mai la chiusura automatica del task non rilascia la memoria usata ? Come debbo agire affinchè la memoria rimanga stabile e non salga piano piano fino all'impossibilità di far continuare a girare le routines ?


Imports System.Diagnostics
Imports System.Globalization
Imports System.Threading.Tasks

Public Class Form1

    Dim MemUsata As String = ""
    Dim TestOrario As String = ""

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Me.CenterToScreen()

        Timer1.Interval = 50
        Timer1.Enabled = True

    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick

        txtMemUsata.AppendText(MemUsata)
        TextBox1.Text = TestOrario

        Dim TEST_TASK_1 As New Task(AddressOf ORARIO)
        TEST_TASK_1.Start()

        Dim TEST_TASK_2 As New Task(AddressOf MEM_USATA)
        TEST_TASK_2.Start()

    End Sub

    Sub ORARIO()
        TestOrario = Format(Now.ToString("G", New CultureInfo("it-IT")))
    End Sub

    Sub MEM_USATA()

        Dim c As Process = Process.GetCurrentProcess()
        MemUsata = String.Empty
        MemUsata &= Format(Now.ToString("G", New CultureInfo("it-IT"))) & " --- "
        MemUsata &= "WS: " & c.WorkingSet / 1024 & " K - "
        MemUsata &= "VM: " & c.PagedMemorySize / 1024 & " K - "
        MemUsata &= "GC: " & GC.GetTotalMemory(True) & " b" & vbCrLf

    End Sub

End Class


Serve un form, un timer e due textbox : uno scrive la memoria usata e l'altro semplicemente aggiorna l'orario.

Grazie per chi vorrà aiutarmi
Modificato da fotosettore2 il 20 marzo 2020 22:47 -
126 messaggi dal 01 febbraio 2017
Salve, approccio una possibile causa .. se nn ricordo male l'unità di ritardo del Timer è millisecondi, e tu lo assegni a 50, quindi ogni 5 centesimi di secondo il tuo pgm dovrebbe eseguire le due SUB separatamente .. può essere pure che il tempo di esecuzione dei due task sia superiore a 50 millisecondi, per cui la 'coda' continua a riempirsi di tread che il tuo pgm non riesce ad evadere ... Prova ad aumentare l'intervallo di tempo (ovvero il ritardo dei task) , oppure usa un'altra tecnica multitasking. Ad esempio, blocchi il timer prima dell'esecuzione dei task (così nn continua ad accodare operazioni) e lo fai ripartire alla fine dell'esecuzione dell'ultima operazione schedulata.

Facci sapere come va.
Gino.

UNSTRING identifier-1 id-2 id-3
DELIMITED BY [ALL] OR [ALL] literal-1 lit-2
INTO {id-4 [DELIMITER IN id-5]
[COUNT IN id-6]}
[WITH POINTER id-7]
[TALLYING IN id-8]
[ON OVERFLOW imperative-statement-1]
[NOT ON OVERFLOW imper-2]
[END-UNSTRING]
17 messaggi dal 30 marzo 2017
Ciao SensoBit
avevo già fatto la prova mettendo 5000 ed il risultato è stato che l'overflow è avvenuto molto molto più avanti nel tempo. Infatti la memoria, sia pure se più lentamente a causa del tempo maggiore di esecuzione, aumenta inesorabilmente lo stesso.
Questo purtroppo significa che non è un problema dovuto al timer e alla velocità delle due routines ...
Provo la seconda soluzione da te proposta ...
Modificato da fotosettore2 il 21 marzo 2020 12:08 -
126 messaggi dal 01 febbraio 2017
Guardando meglio il tuo codice vedo che l'oggetto TEST_TASK_1 e TEST_TASK_2 non sono distrutti a fine esecuzione ... prova a fare il Dispose ...

UNSTRING identifier-1 id-2 id-3
DELIMITED BY [ALL] OR [ALL] literal-1 lit-2
INTO {id-4 [DELIMITER IN id-5]
[COUNT IN id-6]}
[WITH POINTER id-7]
[TALLYING IN id-8]
[ON OVERFLOW imperative-statement-1]
[NOT ON OVERFLOW imper-2]
[END-UNSTRING]
17 messaggi dal 30 marzo 2017
ho aggiunto questo pezzettino

        While FineTask = False

            If TEST_TASK_1.IsCompleted = True And TEST_TASK_2.IsCompleted = True Then
                TEST_TASK_1.Dispose()
                TEST_TASK_2.Dispose()
                FineTask = True
            End If

        End While


FineTask (che regola Timer1.enabled) la faccio diventare false appena partita la routine

ma nulla ... la memoria continua lentamente ma inesorabilmente a salire :-(
126 messaggi dal 01 febbraio 2017
fotosettore2 ha scritto:
ho aggiunto questo pezzettino

        While FineTask = False

            If TEST_TASK_1.IsCompleted = True And TEST_TASK_2.IsCompleted = True Then
                TEST_TASK_1.Dispose()
                TEST_TASK_2.Dispose()
                FineTask = True
            End If

        End While


FineTask (che regola Timer1.enabled) la faccio diventare false appena partita la routine

ma nulla ... la memoria continua lentamente ma inesorabilmente a salire :-(


Ehmm ti ricordo che i tue task sono indipendenti, ed eseguiti ognuno per conto proprio, quindi non è detto siano entrambi completati nello stesso istante .. può essere che task1 ha finito e task2 ancora no, e quindi viene avviato task1 di nuovo, quindi appena finisce task2, c'è task1 attivo e così via.
Prova a fare il dispose autonomamente di ogni task, appena finita la sua esecuzione.

Prova a mettere il dispose, a seguire nel codice dove viene creato l'oggetto.

C'è un'altra soluzione un pò più complicata ... dovesti dichiarare Friend il task, in modo da mantenere il suo stato fra le varie istanze ... lo dichiari una sola volta e lo usi ad ogni ticker, così eviti di istanziarlo ogni volta ... Non so se mi sono spiegato.

Ciao.
Gino.
Modificato da SensoBit il 21 marzo 2020 16:30 -

UNSTRING identifier-1 id-2 id-3
DELIMITED BY [ALL] OR [ALL] literal-1 lit-2
INTO {id-4 [DELIMITER IN id-5]
[COUNT IN id-6]}
[WITH POINTER id-7]
[TALLYING IN id-8]
[ON OVERFLOW imperative-statement-1]
[NOT ON OVERFLOW imper-2]
[END-UNSTRING]
17 messaggi dal 30 marzo 2017
ciao gino
ma io ho messo un AND (non OR) e quindi SOLO SE AMBEDUE GLI iscompleted SONO TRUE timer.enabled diventa nuovamente TRUE
altrimenti non riparte nulla.
dove sbaglio in questa valutazione ?

p.s. confermo che la routine gira e non si ferma. in pratica il timer si abilita e disabilita anche con 50ms (insomma: i task sono completati)

MEMORIA ALLE 14.43 ----> 29.580
MEMORIA ALLE 16.21 ----> 45.550
MEMORIA ALLE 17.15 ----> 51.556

C'è qualcosa che mi/ci sfugge :-(
Modificato da fotosettore2 il 21 marzo 2020 17:16 -
126 messaggi dal 01 febbraio 2017
fotosettore2 ha scritto:
ciao gino
ma io ho messo un AND (non OR) e quindi SOLO SE AMBEDUE GLI iscompleted SONO TRUE timer.enabled diventa nuovamente TRUE
altrimenti non riparte nulla.
dove sbaglio in questa valutazione ?

p.s. confermo che la routine gira e non si ferma. in pratica il timer si abilita e disabilita anche con 50ms (insomma: i task sono completati)

MEMORIA ALLE 14.43 ----> 29.580
MEMORIA ALLE 16.21 ----> 45.550
MEMORIA ALLE 17.15 ----> 51.556

C'è qualcosa che mi/ci sfugge :-(
Modificato da fotosettore2 il 21 marzo 2020 17:16 -


Leggi meglio la mia ultima risposta ... gli oggetti non vengono mai distrutti

Poi c'è una seconda soluzione che ti ho suggerito ...

Infine sarebbe utile postare il codice completo.
Ciao.

UNSTRING identifier-1 id-2 id-3
DELIMITED BY [ALL] OR [ALL] literal-1 lit-2
INTO {id-4 [DELIMITER IN id-5]
[COUNT IN id-6]}
[WITH POINTER id-7]
[TALLYING IN id-8]
[ON OVERFLOW imperative-statement-1]
[NOT ON OVERFLOW imper-2]
[END-UNSTRING]

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.