IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

Est-ce normal tout ces GC


Sujet :

VB.NET

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    505
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Février 2006
    Messages : 505
    Par défaut Est-ce normal tout ces GC
    bonjour à tous

    Est-ce normal tout ces coches du garbage collector dans le run de mon app

    Nom : Diag.jpg
Affichages : 155
Taille : 122,1 Ko

    merci beaucoup

  2. #2
    Membre Expert Avatar de Phil Rob
    Homme Profil pro
    Retraité
    Inscrit en
    Novembre 2013
    Messages
    1 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Novembre 2013
    Messages : 1 613
    Par défaut
    Bonjour,

    Bien malin celui qui pourra te répondre sans avoir examiné ton code ... , et puis, ce n'est peut-être que le fait d'une bonne gestion de la mémoire, le GC fait son travail.

    Il est clair qu'une bonne gestion de la mémoire est utile à l'application et même au système !

    Pour ma part, j'applique toujours quelques principes.

    Toujours utiliser Dispose au sein de la même procédure pour détruire tout instance initiée avec New. si un objet doit être utilisé dans diverses procédures, alors il faut l'instancier à un niveau supérieur (au niveau global, hors procédure). Ne pas oublier Dispose pour un tel objet lors de l'arrêt de l'application, quelle que soit la manière dont on l'arrête. Certaines instances ne propose pas de Dispose mais elle ont alors une autre méthode de libération de la mémoire (par exemple, les fichiers ont la méthode Close).
    Ne oublier de fermer et Disposer aussi, de la même manière que toute autre instance, tous les outils (connexions, commandes, paramèters, DataAdapeter, ...) utilisés lors du travail avec les DB (OleDb, SqlDB, MySqlDB, ...).

    Dans les cas de création de mes objets, je les dote toujours d'un destructeur programmé (lequel fait appel au GC) même si cela n'est pas toujours nécessaire, je m'oblige à considérer la question, pour le cas où ....

    Utiliser du code managé de préférence à tout autre. Notamment, je retire toujours la librairie VisualBasic de mes applications et si j'en ai vraiment besoin, je donne le chemin complet lors de l'appel (par exemple Microsoft.VisualBasic.VBMath.Rnd() pour utiliser Rnd()). J'utiliserai ainsi les conversions avec CType() plutôt que les Val, Str, CInt, CStr, ...

    Après l'application de ces principes, je ne dois plus guère me soucier de la santé de la mémoire, quoique fasse le GC.

    J'espère que ma prose te servira ...

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    505
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Février 2006
    Messages : 505
    Par défaut merci de ta réponse
    je crois que je suis une bonne technique pour l'utilisation de mes variables

    voici quelques exemples:

    pour le chargement de mon dataset je fais comme suis

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     If _Ds IsNot Nothing Then
                        '_Ds.Dispose()
                        _Ds = Nothing
                    End If
                    _Ds = New DataSet
     
                    '----------------------------------------------------------------------------
                    Da = New OleDbDataAdapter("SELECT TblSymbole.* FROM TblSymbole WHERE Active=True;", My.Settings.DbConn)
                    Da.Fill(_Ds, "TblSymbole")
                    Da = Nothing
     
                    With _Ds.Tables("TblSymbole").Columns("Id_Symb")
                        .AutoIncrement = True
                        .AutoIncrementSeed = 1
                        .AutoIncrementStep = 1
                    End With
                    '----------------------------------------------------------------------------
                    Da = New OleDbDataAdapter("SELECT TblIndice.* FROM TblIndice WHERE Active=true;", My.Settings.DbConn)
                    Da.Fill(_Ds, "TblIndice")
                    Da = Nothing
     
                    With _Ds.Tables("TblIndice").Columns("Id_Indice")
                        .AutoIncrement = True
                        .AutoIncrementSeed = 1
                        .AutoIncrementStep = 1
                    End With
                    '----------------------------------------------------------------------------
    il me manquait le dispose du "Da"

    Pour le chargement d'une datatable je vais comme suis

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    Dim Nrw As DataRow = DtHistorie.NewRow
     
                                        Nrw("DataDate") = D_Hist.eoddataDate
                                        Nrw("Id_Symb") = Id_Symb
     
                                        If Not D_Hist.open = Nothing AndAlso D_Hist.open.Contains("."c) Then
                                            D_Hist.open = D_Hist.open.Replace(".", ",")
                                        End If
     
                                        If IsNumeric(D_Hist.open) Then
                                            Nrw("open") = CDbl(D_Hist.open)
                                        Else
                                            Nrw("open") = DBNull.Value
                                        End If
     
                                        If Not D_Hist.high = Nothing AndAlso D_Hist.high.Contains("."c) Then
                                            D_Hist.high = D_Hist.high.Replace(".", ",")
                                        End If
                                        If IsNumeric(D_Hist.high) Then
                                            Nrw("high") = CDbl(D_Hist.high)
                                        Else
                                            Nrw("high") = DBNull.Value
                                        End If
     
                                        If Not D_Hist.low = Nothing AndAlso D_Hist.low.Contains("."c) Then
                                            D_Hist.low = D_Hist.low.Replace(".", ",")
                                        End If
                                        If IsNumeric(D_Hist.low) Then
                                            Nrw("low") = CDbl(D_Hist.low)
                                        Else
                                            Nrw("low") = DBNull.Value
                                        End If
     
                                    Etc.
     
                                        DtHistorie.Rows.Add(Nrw)
                                        Nrw = Nothing

  4. #4
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    505
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Février 2006
    Messages : 505
    Par défaut Autre question
    quel code est le mieux?

    code1
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     Dim Var1 As Integer = Nothing
            For y As Integer = 0 To 10
                Var1 = y
                'Autre code quelquonque
     
                Var1 = Nothing
            Next
    code2
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    For y As Integer = 0 To 10
     
                Dim Var2 As Integer = y
     
                'Autre code quelquonque
     
                Var2 = Nothing
            Next
    habituellement j'utilise le code1 car je déclare 1 fois la variable

  5. #5
    Membre Expert Avatar de Phil Rob
    Homme Profil pro
    Retraité
    Inscrit en
    Novembre 2013
    Messages
    1 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Novembre 2013
    Messages : 1 613
    Par défaut
    Attention, Da = Nothing n'est pas du tout équivalent à Da.Dispose.

    Lorsque que tu écris Da = New OleDbDataAdapter( .... ), tu réserves une place en mémoire pour toutes les données d'un objet de type DataAdapter. L'adresse de cette zone mémoire est livrée dans la variable Da.

    Quand tu écris Da = Nothing, tu mets la valeur nulle dans cette variable qui contient l'adresse de la zone mémoire réservée, laquelle devient ainsi inaccessible MAIS n'est pas désignée au GC pour récupération dès que possible. Cette zone mémoire reste inutilement réservée dans la mémoire probablement jusqu'à l'arrêt de ton programme. Cette zone mémoire est donc perdue pour tout autre chose, de ton application ou du système. Au prochain, New, ce sera une autre zone mémoire qui sera réservée et petit à petit, ton application "mange" la mémoire ...

    Si tu écris Da.Dispose, tu indiques explicitement au GC qu'il peut libérer cette zone mémoire au profit de tout autre besoin. Le GC n'exécutera pas cette libération instantanément, mais très rapidement, dès qu'il en a le temps ... Lors d'un prochain New, la même zone mémoire pourra être réutilisée ou pas, c'est sans importance.

    L'usage de Da = Nothing est une ancienne façon de faire (VBA, VB5 et VB6) qui reste utile pour des objets qui ne sont pas instanciés avec New. Cela a surtout pour but de "faire propre", cela n'a jamais libéré une zone mémoire réservée mais quand on ne programme pas en DotNet, ou bien qu'on utilise du code non managé (avec des fonctions comme CreateObject(), par exemple), on n'a pas d'autre choix que d'attendre que le système récupère les zones de mémoires perdues après la fin de l'application.

    La réservation d'une zone mémoire avec New est l'obtention de l'adresse d'une zone mémoire située dans le TAS. La variable (qui n'est finalement qu'un pointeur) reçoit l'adresse du premier octet de la zone. Il est clair que remplacer cette adresse par 0 ne libèrera pas la zone mémoire.

    Dans ton premier extrait de code, tu instancies 2 OleDbDataAdpter. cela fait 2 zones mémoires qui restent perdues (après leur usage) par Da = Nothing. Et 2 zones supplémentaires sont instanciées à chaque appel de ce code. Si l'application passe 20 fois sur ce code, l'application laisse 40 zones OleDbDataAdpter perdue dans la mémoire. Quand l'application s'arrêtera, c'est le système qui aura beaucoup de travail pour réorganiser sa mémoire ...

    Dans le second extrait de code, Nrw n'est pas instanciée avec New, il faut voir si un Dispose est disponible sans erreur (Nrw.Dispose), auquel cas, il faut l'utiliser. Dans le cas contraire Nrw = Nothing "fait propre"

    A demain peut-être, je lâche mon PC pour ce soir (ici, il est 23h).

  6. #6
    Membre Expert Avatar de Phil Rob
    Homme Profil pro
    Retraité
    Inscrit en
    Novembre 2013
    Messages
    1 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Novembre 2013
    Messages : 1 613
    Par défaut
    Ton "Autre question" et mon message précédent se sont croisés ...

    Alors, en vitesse, s'il faut vraiment choisir entre ces 2 codes, je prendrais le 1er. Mais l'usage de Nothing dans ce cas est un non-sens (sans gravité) quel que soit la version du VB.
    Var1 (tout comme Var2) est une variable de type Integer : la valeur nulle d'un Integer est 0.

    La valeur Nothing s'emploie uniquement avec des pointeurs (ou références), même si dans le cas des déclaration avec New, on parle d'instances.

    Bonne nuit ...

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    505
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Février 2006
    Messages : 505
    Par défaut Merci beaucoup vieux
    Sache que c'est avec un très grand respect que j'ose dire vieux à cause du "Enseignant retraité" hehe!

    Merci beaucoup c'est très instructif, et mes lignes de codes seront sûrement meilleurs maintenant.

    bonne journée

  8. #8
    Membre Expert Avatar de Phil Rob
    Homme Profil pro
    Retraité
    Inscrit en
    Novembre 2013
    Messages
    1 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Novembre 2013
    Messages : 1 613
    Par défaut
    Merci, bonne journée à toi aussi (quand tu te lèveras, dans quelques heures ... ).

    Voici un extrait de manuel scolaire pour compléter (ou reformuler) mes explications d'hier : RamasseMiettes.pdf (t'inquiéte pas, il n'y a ± qu'une seule page).

    Bonne lecture

  9. #9
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    505
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Février 2006
    Messages : 505
    Par défaut finalement je comprend pas ça
    je croyais que c'était la bonne façon mais mes colonnes ne s'affiche pas que j'active le dispose

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     MyCol1 = New ColumnHeader
            With MyCol1
                .Text = "Id"
                .Width = 50
                .TextAlign = HorizontalAlignment.Left
            End With
            LVSymb.Columns.Add(MyCol1)
            MyCol1.Dispose()
            MyCol1 = Nothing
    je croyais qu'après avoir assigné la colonne de mon lvsymb je pouvais détruire MyCol1

  10. #10
    Membre Expert Avatar de Phil Rob
    Homme Profil pro
    Retraité
    Inscrit en
    Novembre 2013
    Messages
    1 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Novembre 2013
    Messages : 1 613
    Par défaut
    Déjà levé ? ou bien tu ne t'es pas encore couché ?

    Le problème que tu rencontre est bien normal. Puisque New te donne un "pointeur" sur les données d'un objet instancié et que Dispose détruit l'objet pointé.
    La ligne MyCol1.Dispose détruit l'objet pointé et tu perds les données qui ne s'affichent donc plus.

    Je n'ai jamais été fan du ListView (je préfère le DataGridView) mais j'ai retrouvé le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    MaListView.Columns.Add("Libellé", Largeur, Alignement)
     
    ' soit, selon ton exemple :
     
    LVSymb.Columns.Add("Id", 50, HorizontalAlignment.Left)
    Cette manière d'ajouter les colonnes au ListView me dispense de les instancier explicitement et je ne dois pas m'occuper de leur Dispose.



    J'ajoute en vitesse, ce problème te prouve bien que Dispose fait réellement autre chose que le Nothing seul, lequel ne libère pas la mémoire.

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    505
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Février 2006
    Messages : 505
    Par défaut merci Phil
    En fait je travaille de nuit,

    C'est plus justicieux de faire comme tu le suggères

    Merci du temps accordé
    Bonne journée

  12. #12
    Membre Expert Avatar de Phil Rob
    Homme Profil pro
    Retraité
    Inscrit en
    Novembre 2013
    Messages
    1 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Novembre 2013
    Messages : 1 613
    Par défaut Suite...
    Bonjour,

    En repensant au problème du Da = New OleDbDataAdapter("SELECT TblSymbo ... ... que tu ne peux "Disposer" sans perdre les données, je t'envoie ici quelques extraits de codes illustrant une "meilleure" façon de faire.
    La question est la suivante : Comment détruire l'objet de connexion quand il a fini son job sans perdre les données que je veux afficher ?
    La réponse est la suivante : Garder les données dans un DataTable (ou plusieurs, je peux ajouter un DataTable par type de SELECT, encore qu'on puisse aussi faire des sélection sur le DataTable lui-même) idéalement stocké(s) dans un DataSet, ce dernier n'étant détruit qu'avant de quitter l'application. Au besoin, on le vide pour remplacer toutes ses données.

    Au niveau global de la page de code (excuse moi, les noms des variables et procédures sont en espagnol, mais facile à comprendre ... ) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Imports System.Data.OleDb
     
    Public Class FTestDB
     
        Dim MiConexion As New OleDbConnection
        Dim MisDatos As New DataSet
        Dim NombreTablaEnDB As String           ' nom de la table
        Dim MiComando As New OleDbCommand
     
    ' ... ... ...
    La définition de la chaine de connexion (qui est employée lors de la lecture de la DB) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        Private Sub ParametroConexion()
     
            Dim RutaYNombreDB As String = "D:\Tmp\TestAccesDBSimpleConMostrar\MonStock2013.accdb"  ' Chemin et nom complet
            MiConexion.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & RutaYNombreDB & ";"  ' Ejecutar en x64
     
            NombreTablaEnDB = "TProductos"   ' la table qui m'inétresse
        End Sub
    Lecture de la DB avec un DataAdapter :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
        Private Sub CargarLaTablaConAdapter() ' con DataAdapter   plus simple car la DataTabla est créee automatiquement
     
            If MisDatos.Tables.Count > 0 Then  ' pour plusieurs chargements
                MisDatos.Tables.Clear()     ' nettoyage de DataSet, si des DataTable doivent être retiré, la méthode Clear fera le nécessaire
            End If
     
            ParametroConexion()
     
            Dim UnaTabla As New DataTable      ' Instanciation du DataTable
            Dim Consulta As String
     
            Consulta = "SELECT * FROM " & NombreTablaEnDB
     
            Dim MiAdapter As OleDbDataAdapter = New OleDbDataAdapter(Consulta, MiConexion)
     
            MiAdapter.Fill(UnaTabla)
            UnaTabla.TableName = NombreTablaEnDB
            MisDatos.Tables.Add(UnaTabla)      ' ajout du DataTable au DataSet global et permanent
     
            MiAdapter.Dispose()     ' Pas de Dispose du DataTable
            MiConexion.Close()
     
            MostrarDatos()   ' procédure d'affichage dans divers composants
     
        End Sub
    ' ... ... ...
    On peut faire une lecture de la DB avec un DataReader (ceci impose de créer "manuellement" le DataTable) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
       Private Sub CargarLaTablaConDataReader()   ' con DataReader
     
            If MisDatos.Tables.Count > 0 Then  ' Para muchas pruebas
                MisDatos.Tables.Clear()
            End If
     
            ParametroConexion()
            MiConexion.Open()
     
            Dim UnaTabla As New DataTable
     
            ' Connexion effective 
            MiComando = MiConexion.CreateCommand()
            MiComando.CommandType = CommandType.Text
            MiComando.CommandText = "SELECT * FROM " & NombreTablaEnDB
     
            Dim UnosDatos As OleDbDataReader
            UnosDatos = MiComando.ExecuteReader()
            ' Crear colunas en  DataTabla
            For C As Integer = 0 To UnosDatos.FieldCount - 1
                UnaTabla.Columns.Add(UnosDatos.GetName(C))
            Next
     
            UnaTabla.TableName = NombreTablaEnDB
     
            Do While UnosDatos.Read
                UnaTabla.Rows.Add()
                For C As Integer = 0 To UnosDatos.FieldCount - 1
                    UnaTabla.Rows(UnaTabla.Rows.Count - 1)(C) = UnosDatos.Item(C)
                Next
            Loop
            MisDatos.Tables.Add(UnaTabla)
     
            UnosDatos.Close()
            MiConexion.Close()
     
            MostrarDatos()
     
        End Sub
    ' ... ... ...
    Et pour afficher les données :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
        Private Sub MostrarDatos()
     
            For Each C As Control In Me.Controls  ' Pour tests mulitiples, il est nécesaire d'effacer les ancienne liaisons
                Try
                    C.DataBindings.Clear()
                Catch
                End Try
            Next
     
            ' DataGridView
            DGVTest.DataSource = MisDatos.Tables(NombreTablaEnDB)
     
            ' ComboBox
            CBTest.DataSource = MisDatos.Tables(NombreTablaEnDB)
            CBTest.DisplayMember = "Articulos"
            CBTest.ValueMember = "Id"
     
            ' ListBox
            LBTest.DataSource = MisDatos.Tables(NombreTablaEnDB)
            LBTest.DisplayMember = "Articulos"
     
            ' TextBox
            TBTest.DataBindings.Add("Text", MisDatos.Tables(NombreTablaEnDB), "Stock_A")
     
        End Sub
    Et ne pas oublier de nettoyer ce qui reste encore en mémoire avant de partir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        Private Sub FTestDB_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
            Try
                MisDatos.Dispose()
            Catch ex As Exception
     
            End Try
        End Sub
    Ci-joint, ce projet test complet. Tu peux l'exécuter en modifiant la chaine de connexion selon la configuration de ton PC : TestAccesDBSimpleConMostrar.zip.

    Bonne journée ...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. C'est quoi toutes ces applications ?
    Par zecreator dans le forum Android
    Réponses: 1
    Dernier message: 31/12/2014, 08h51
  2. Sniffeur RAW - Capture minimale - Est ce normal ?
    Par MonsieurAk dans le forum Développement
    Réponses: 11
    Dernier message: 27/04/2006, 08h35
  3. [HIBERNATE] C'est quoi toutes ces versions ?
    Par _beber85 dans le forum Hibernate
    Réponses: 9
    Dernier message: 11/04/2006, 10h17
  4. Modifier une requête dans toutes ces tables...
    Par SnickeursMan dans le forum Requêtes
    Réponses: 6
    Dernier message: 14/12/2005, 13h08
  5. [C#][Windows application] - Heure de l'est, heure normal
    Par Erakis dans le forum Windows Forms
    Réponses: 4
    Dernier message: 03/10/2005, 16h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo