bonjour à tous
Est-ce normal tout ces coches du garbage collector dans le run de mon app
merci beaucoup
bonjour à tous
Est-ce normal tout ces coches du garbage collector dans le run de mon app
merci beaucoup
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 ...![]()
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
il me manquait le dispose du "Da"
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 '----------------------------------------------------------------------------
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
quel code est le mieux?
code1
code2
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
habituellement j'utilise le code1 car je déclare 1 fois la variable
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
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).
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 ...![]()
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
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![]()
je croyais que c'était la bonne façon mais mes colonnes ne s'affiche pas que j'active le dispose
je croyais qu'après avoir assigné la colonne de mon lvsymb je pouvais détruire MyCol1
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
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 :
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.
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)
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.
En fait je travaille de nuit,
C'est plus justicieux de faire comme tu le suggères
Merci du temps accordé
Bonne journée
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 ... ) :
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
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 ' ... ... ...
Lecture de la DB avec un DataAdapter :
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
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 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 ' ... ... ...
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
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 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
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
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.
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
Bonne journée ...![]()
Partager