Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 11
  1. #1

    Problema Eccessivo Uso Memoria

    Mi son appena avvicinato alla programmazione con VB .NET 2005, e per studiare un po’ il linguaggio sto creando un classico programmino stile rubrica (anche se ben accessoriata) che si interfaccia con un database SQL Server 2005.

    Ho il problema che il software fa un uso smisurato della memoria; basta avviare il programma (che all'avvio è solo 1 form con un banale menù per avviare gli altri form) e già son 12Mb utilizzati, se apro il form per gestire la rubrica (una tabella con circa 30 campi), gestita mediante table adapter creato col wizard, l’occupazione di memoria schizza a 25Mb, e la cosa assurda è che in tabella ci ho messo giusto un paio di record tanto per testare il funzionamento! Va da sé che se poi apro anche altri form l’uso della memoria continua ad aumentare in maniera esponenziale; immagino che il problema stia nel fatto che i dati son caricati tutti in memoria, anche se non riesco a capire come 3 record possan occupare 25Mb !!!

    Inoltre, chiudendo il form la memoria non viene comunque scaricata; ho provato a usare il sia il comando clear che dispose per il dataset, senza risultato. Avevo anche provato a gestire inserimenti e visualizzazioni da codice con comandi sql anziché usare i tool visuali, ma aldilà del maggior tempo di programmazione ottenevo che si occupava meno memoria ma quando c’era da far un insert o una select i tempi eran biblici (almeno usando i dataset ci mette di più a caricare ma una volta che son in memoria si procede ragionevolmente spediti)

    Come faccio a ridurre drasticamente il consumo di memoria e ottenere contemporaneamente una buona velocità di esecuzione del programma? Può aiutare creare più dataset anziché uno unico che contiene i table adapter per tutte le tabelle?

    Grazie in anticipo a chiunque mi darà una mano

  2. #2
    Utente di HTML.it L'avatar di cassano
    Registrato dal
    Aug 2004
    Messaggi
    3,002
    il dispose delle variabili e le connessioni le chiudi ???

  3. #3
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472

    Re: Problema Eccessivo Uso Memoria

    Originariamente inviato da hwplanet
    Ho il problema che il software fa un uso smisurato della memoria; basta avviare il programma (che all'avvio è solo 1 form con un banale menù per avviare gli altri form) e già son 12Mb utilizzati, se apro il form per gestire la rubrica (una tabella con circa 30 campi), gestita mediante table adapter creato col wizard, l’occupazione di memoria schizza a 25Mb, e la cosa assurda è che in tabella ci ho messo giusto un paio di record tanto per testare il funzionamento! Va da sé che se poi apro anche altri form l’uso della memoria continua ad aumentare in maniera esponenziale; immagino che il problema stia nel fatto che i dati son caricati tutti in memoria, anche se non riesco a capire come 3 record possan occupare 25Mb!!!
    Welcome to the .NET world!

    Lavorando con un "ambiente gestito" quale è quello offerto dal CLR di .NET, non è possibile aspettarsi sempre un comportamento lineare in termini di fattori occupazionali e prestazionali dell'applicazione, poiché questi aspetti dipendono da molteplici fattori su cui il programmatore non ha una diretta influenza e che, a seconda dello stato del sistema, possono variare.

    Quando il CLR esegue codice, controlla la quantità di memoria disponibile e può, all'occorrenza, allocarne più di quanto non sia strettamente necessario poiché le condizioni del sistema lo consentono e questo può eventualmente favorire prestazioni più elevate in seguito; oppure ancora, il CLR potrebbe rilevare una particolare CPU e ottimizzare il codice nativo generato per eseguire più celermente su quella architettura.

    Quando invece le risorse sono scarse, il CLR può optare per una conformazione più conservativa rispetto alle risorse del sistema.

    Nel caso della velocità, è possibile che a diverse esecuzioni si abbiano tempi differenti per lo stesso processo; può accadere infatti che, nell'eseguire una determinata operazione magari anche lunga, il CLR intervenga rilasciando la memoria per gli oggetti che sono stati sottoposti a Garbage Collection, oppure questo rilascio più essere dilazionato nel tempo per diversi motivi che fanno capo all'architettura interna dello stesso runtime.

    Originariamente inviato da hwplanet
    Inoltre, chiudendo il form la memoria non viene comunque scaricata
    Chiudere il form non significa distruggere l'oggetto: è un'operazione che viene avviata solamente tramite il Garbage Collector quando non vi sono più riferimenti validi ad un determinato oggetto.

    Originariamente inviato da hwplanet
    ho provato a usare il sia il comando clear che dispose per il dataset, senza risultato.
    Anche eseguendo Dispose, tutto ciò che viene rilasciato sono le risorse non gestite dal framework (ad esempio, le risorse native, i canali di I/O aperti su file o su socket, ecc.) ma non gli oggetti stessi che, come descritto prima, sono assoggettati al volere del Garbage Collector.

    Originariamente inviato da hwplanet
    Avevo anche provato a gestire inserimenti e visualizzazioni da codice con comandi sql anziché usare i tool visuali, ma aldilà del maggior tempo di programmazione ottenevo che si occupava meno memoria ma quando c’era da far un insert o una select i tempi eran biblici (almeno usando i dataset ci mette di più a caricare ma una volta che son in memoria si procede ragionevolmente spediti)
    In questo frangente, controllerei che non siano presenti problemi nella connessione al DB e verificherei l'ottimizzazione dello stesso. Non ho mai avuto grossi problemi prestazionali con le classi per l'accesso ai dati. Quale famiglia di classi ADO.NET usi per il collegamento?

    Originariamente inviato da hwplanet
    Come faccio a ridurre drasticamente il consumo di memoria e ottenere contemporaneamente una buona velocità di esecuzione del programma? Può aiutare creare più dataset anziché uno unico che contiene i table adapter per tutte le tabelle?
    Rispondo dicendo solamente che se ti aspetti di vedere scendere l'occupazione di RAM a pochi Kb, puoi già scordartelo in quanto generalmente qualsiasi applicazione Windows Forms ha un limite inferiore che difficilmente si può abbassare senza "salti mortali".

    Del resto, bisogna tenere conto del fatto che il CLR è un elemento attivo che svolge determinati servizi, pertanto occorre che vi sia posto in memoria anche per il codice che lo costituisce affinché l'applicazione possa beneficiarne per svolgere il proprio compito.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  4. #4
    Il sistema che sto usando è un normale P4 2.8Ghz con 512Mb ram ... quindi se ho ben capito trovando una buona disponibilità di RAM e di CPU il CLR alloca molta memoria ... mentre magari "per assurdo" trovandosi in un P3 1Ghz con 256Mb di ram magari anzichè 25Mb ne userebbe ad esempio 15 ... è così ?!

    Altra cosa ... quindi io devo comunque usare il dispose per i form, i dataset etc. ma poi magari quella memoria sarà liberata (ad esempio) dopo 1minuto, 2 minuti, secondo il volere della Garbage Collection ?!

    Per quanto riguarda il codice scritto per gestire direttamente i dati, questo è un esempio banale:

    codice:
            'Prima di tutto richiamo la classe per la gestione dell'Sql
       Imports System.Data.SqlClient
    
            'Setto i parametri di connessione al Database
            Dim myConnectionString As String = "Data Source=.\SQLEXPRESS;AttachDbFilename=""C:\Programmi\Microsoft SQL Server\MSSQL.1\MSSQL\Data\Test.mdf"";Integrated Security=True;Connect Timeout=30;User Instance=True"
            'Creo la connessione al Server SQL
            Dim myConnection As SqlConnection = New SqlConnection(myConnectionString)
    
            'Creo la query SQL da eseguire
            Dim myQuery As String
    
            'Assegno alla query il testo di una InputBox
            myQuery = Query.Text
    
            'Creo il comando SQL e lo faccio eseguire
            Dim myCommand As SqlCommand = New SqlCommand(myQuery, myConnection)
            myConnection.Open()
            Dim myReader As SqlDataReader = myCommand.ExecuteReader()
    
            'Creo un DataTable in cui carico i risultati della query
            Dim myTable As DataTable = New DataTable()
            myTable.Load(myReader)
            'Mostro i Risultati della Query nel DataGrid
            DataGridView1.DataSource = myTable
    E' più scomodo programmare così rispetto al lasciar fare a VB Studio, ma a parte questo quando eseguivo il comando ci metteva parecchio, mentre usando gli strumenti visuali ripeto una volta che ha caricato in memoria va spedito.

    Ovviamente non mi aspetto di vedere scendere a 100Kb l'occupazione della memoria, ma mi chiedo solo ... se anzichè 3 record ce ne inserisco 10.000 ... che fa, mi chiede 4Gb di Ram su un biprocessore ?!! Poi per curiosità ho preso un programma scaricato da internet, fatto in VB6 che si collega a un database MSDE 2000 ... con dentro decine di migliaia di record occupa 10Mb di memoria ... possibile che io sia così negato che faccio 1000 volte peggio?!!


    Altra cosa che non capisco ... apro il form, senza far alcunchè lo richiudo, la dinamica della memoria è la seguente:

    12Mb Apro il programma
    25Mb Apro il form della rubrica
    25Mb Chiudo il form della rubrica
    26Mb Riapro lo stesso form
    26Mb Lo richiudo
    27Mb Lo riapro

    ... e così via. Sottolineo che per la sola apertura non setto nè variabili nè costanti nè nulla. Il form è semplicemente il classico schedario che permette di scorrere tra i record e inserisli/aggiornarli/eliminarli ... senza neanche usare codice "mio" ma appoggiandomi agli strumenti di sviluppo visuale di VB Studio.

    Quindi, per esser precisi, Creo il programma, ci aggiungo un form, creo un dataset con i datatable di tutte le tabelle del database, e dal box datasource trascino nel designer la tabella ... !

    Inoltre, per curiosità ho provato a creare altri 2 form che si collegano ad altre 2 tabelle ... anche queste con pochissimi record ... il risultato è che aprendoli tutte e tre assieme arrivo a 50Mb di occupazione di memoria, e ripeto i dati son irrisori!! Che 10record occupino 50Mb ha dell'incredibile!

  5. #5
    Originariamente inviato da cassano
    il dispose delle variabili e le connessioni le chiudi ???
    Per la sola apertura del form non setto variabili, di conseguenza non ne faccio il dispose ... per quanto riguarda la chiusura della connessione invece no, non lo faccio per il semplice motivo che non so come si fa!
    Nel senso che non ho scritto il codice che apre la connessione, estrapola i dati etc. ma ho fatto tutto visualmente con i tool di VB Studio, quindi fa tutto lui ... come faccio a dirgli di chiuder la connessione?!

  6. #6
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472
    Originariamente inviato da hwplanet
    Il sistema che sto usando è un normale P4 2.8Ghz con 512Mb ram ... quindi se ho ben capito trovando una buona disponibilità di RAM e di CPU il CLR alloca molta memoria ... mentre magari "per assurdo" trovandosi in un P3 1Ghz con 256Mb di ram magari anzichè 25Mb ne userebbe ad esempio 15 ... è così ?!
    Diciamo che ne userebbe tendenzialmente meno. Quanto di meno, non credo sia determinabile con precisione.

    Originariamente inviato da hwplanet
    Altra cosa ... quindi io devo comunque usare il dispose per i form, i dataset etc. ma poi magari quella memoria sarà liberata (ad esempio) dopo 1minuto, 2 minuti, secondo il volere della Garbage Collection ?!
    Sì. Non penso che vi saranno mai cicli così ampi di minuti, ma dal punto di vista teorico si potrebbe far finta che sia così, se fa comodo.

    Originariamente inviato da hwplanet
    Per quanto riguarda il codice scritto per gestire direttamente i dati, questo è un esempio banale [...]
    Nel codice non vedo nulla di scandaloso.

    Originariamente inviato da hwplanet
    Ovviamente non mi aspetto di vedere scendere a 100Kb l'occupazione della memoria, ma mi chiedo solo ... se anzichè 3 record ce ne inserisco 10.000 ... che fa, mi chiede 4Gb di Ram su un biprocessore ?!!
    No, ovviamente, per il principio espresso prima: la quantità di risorse da allocare dipende ovviamente dalle strutture dati che si creano, ma è possibile che, in presenza di ampia disponibilità, venga preallocata più memoria, ma questo non significa tenere valido il rapporto tra la memoria occupata e moltiplicare.

    Originariamente inviato da hwplanet
    Poi per curiosità ho preso un programma scaricato da internet, fatto in VB6 che si collega a un database MSDE 2000 ... con dentro decine di migliaia di record occupa 10Mb di memoria ... possibile che io sia così negato che faccio 1000 volte peggio?!!
    Non è un problema tuo, o almeno non sembra.

    Originariamente inviato da hwplanet
    Altra cosa che non capisco ... apro il form, senza far alcunchè lo richiudo, la dinamica della memoria è la seguente [...]
    Dovresti verificare se la quantità di memoria aumenta con un numero significativo (almeno un centinaio) di aperture e chiusure. E' possibile inoltre che rimanga da qualche parte un riferimento al form che viene chiuso, ma senza il codice sorgente non è possibile determinarlo.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  7. #7
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472
    Originariamente inviato da hwplanet
    Nel senso che non ho scritto il codice che apre la connessione, estrapola i dati etc. ma ho fatto tutto visualmente con i tool di VB Studio, quindi fa tutto lui ... come faccio a dirgli di chiuder la connessione?!
    E' sempre bene chiudere la connessione subito dopo l'uso, ma è solamente un problema di rilasciare il prima possibile risorse utili al sistema, ma è ininfluente nel nostro caso: quando tutti i riferimenti alla connessione dati di cui parliamo sono spariti, l'oggetto che rappresenta la connessione viene considerato valido candidato per la Garbage Collection, viene "finalizzato" (la connessione viene chiusa) e successivamente rimosso dalla memoria.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  8. #8
    Anzitutto grazie per la disponibilità

    Dunque, Ho provato ad aspettare del tempo per vedere se viene liberata la memoria ... dopo 3 minuti che ho chiuso il form è sempre uguale l'occupazione di memoria.

    Ho provato anche a chiudere ed aprire in rapida sequenza il form ... alla prima apertura occupazione memoria 25Mb, dopo 30 aperture 41Mb, dopo 60 siamo a 56,5Mb dopo 100 siam a 75Mb ... e anche aspettando per vedere se libera la memoria rimane fermo a 75Mb ...

    Ti posto il codice sorgente del form, è di una semplicità estrema...

    codice:
    Public Class ContactAna
    
        Private Sub ContactAnaBindingNavigatorSaveItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ContactAnaBindingNavigatorSaveItem.Click
            Dim Codice As String
    
            If (CodiceTextBox.Text = "") Then
                Codice = Me.NumberTableAdapter.GetNextNumber("ContactAna", "0")
                Me.CodiceTextBox.Text = Codice
            End If
            
            Me.Validate()
            Me.ContactAnaBindingSource.EndEdit()
            Me.ContactAnaTableAdapter.Update(Me.GeCoNETDataSet.ContactAna)
    
        End Sub
    
        Private Sub ContactAna_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            'TODO: This line of code loads data into the 'GeCoNETDataSet.Indirizzi' table. You can move, or remove it, as needed.
            Me.IndirizziTableAdapter.Fill(Me.GeCoNETDataSet.Indirizzi)
            'TODO: This line of code loads data into the 'GeCoNETDataSet.ContactCat' table. You can move, or remove it, as needed.
            Me.ContactCatTableAdapter.Fill(Me.GeCoNETDataSet.ContactCat)
            'TODO: This line of code loads data into the 'GeCoNETDataSet.Province' table. You can move, or remove it, as needed.
            Me.ProvinceTableAdapter.Fill(Me.GeCoNETDataSet.Province)
            'TODO: This line of code loads data into the 'GeCoNETDataSet.ContactAna' table. You can move, or remove it, as needed.
            Me.ContactAnaTableAdapter.Fill(Me.GeCoNETDataSet.ContactAna)
    
        End Sub
    
        Private Sub ContactAna_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
            Me.Validate()
            Me.ContactAnaBindingSource.EndEdit()
            Me.ContactAnaTableAdapter.Update(Me.GeCoNETDataSet.ContactAna)
    
            Me.Dispose()
            Me.GeCoNETDataSet.Clear()
            Me.GeCoNETDataSet.ContactAna.Dispose()
    
        End Sub
    
    
    End Class

  9. #9
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472
    Senza scendere nei dettagli, non vedo nulla di male nel codice, quindi suppongo che tutto rientri nella normalità. Al di là di questo fattore, ciò che dovresti verificare è che l'applicazione non allochi più memoria del dovuto quando le condizioni del sistema non lo permettono.

    Prova ad aggiungere in punti strategici (ad esempio, dopo che un oggetto ha cessato di avere riferimenti) una chiamata al metodo Collect della classe System.GC, benché suppongo che non avrà grandi effetti.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  10. #10
    Originariamente inviato da alka
    Senza scendere nei dettagli, non vedo nulla di male nel codice, quindi suppongo che tutto rientri nella normalità. Al di là di questo fattore, ciò che dovresti verificare è che l'applicazione non allochi più memoria del dovuto quando le condizioni del sistema non lo permettono.

    Prova ad aggiungere in punti strategici (ad esempio, dopo che un oggetto ha cessato di avere riferimenti) una chiamata al metodo Collect della classe System.GC, benché suppongo che non avrà grandi effetti.

    Ciao!
    Adesso mi studio un attimo il metodo Collect e provo ad usarlo, poi ti dico se ha sortito qualche effetto ...

    A questo punto mi sorge un dubbio... ma può essere che aldilà della formale correttezza del mio codice sia il mio approccio alla faccenda che sia poco efficiente? In altre parole, la gestione di uno schedario, quale sostanzialmente è il form del test, fatta così richiede che vengano caricati in memoria tutti i dati, mentre magari con altri sistemi si può caricare solo quelli che effettivamente servono in quanto mostrati a video.

    Esempio pratico: ora quando apro il form vien caricato in memoria il contenuto della tabella, e poi tramite il BindingNavigator passo da un record all'altro. Se invece nella query del datatable metto un parametro per cui debba indicare il codice del record e solo quello viene caricato in memoria, c'è poi un metodo "semplice" per scorrere comunque i record?

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.