Optimiser du code prennant beacoup trop de mémoire VB.NET

Résolu
dimitriusai Messages postés 76 Date d'inscription lundi 6 novembre 2006 Statut Membre Dernière intervention 7 mai 2009 - 8 mars 2008 à 08:21
laurent207 Messages postés 101 Date d'inscription jeudi 31 janvier 2002 Statut Membre Dernière intervention 11 avril 2008 - 11 avril 2008 à 13:35
Amis programmeurs du week end, bonjour.
J'ai dévelloppé une petite application qui a mes yeux semblent avoir un soucis, en effet, celle ci prend de la mémoire de facon démessurée, elle démarre à 10000ko et ne fait qu'augmenter.

Le problème ne semble pas venir de la connection sql car en la commentant, cela fait le même problème. Je crois que c'est à cause des WMI, si qqun a une idée

Imports System
Imports System.EventArgs
Imports System.Management
Imports System.Threading

Public Class Service1

    'Ip du serveur MySql.
    Dim SQL_server As String = "**********"
    'User id MySql.
    Dim SQL_userid As String = "*******"
    'User password Mysql.
    Dim SQL_password As String = "**************"
    'Database MySql.
    Dim SQL_DATABASE As String = "************"
    Dim my_memory As Double
    Dim my_memory_total(4) As Double
    Dim my_server As String
    Dim my_cpu As Double
    Dim my_cpu_total(4) As Double
    Dim my_cpu_load As Double
    Dim my_cpu_frequency_max As Integer
    Dim my_cpu_frequency_use As Integer
    Dim boucle As String = ""

    Dim VDLB_VAR As New VDLB()

    Protected Overrides Sub OnStart(ByVal args() As String)
        Perf()
        ' Ajoutez ici le code pour démarrer votre service. Cette méthode doit
        ' démarrer votre service.
    End Sub

    Protected Overrides Sub OnStop()

        ' Ajoutez ici le code pour effectuer les destructions nécessaires à l'arrêt de votre service.
    End Sub

    Sub Perf()
        Do
            Dim i As Integer
            For i = 0 To 4

                Try
                    Dim searcher As New ManagementObjectSearcher( _
                        "root\CIMV2", _
                        "SELECT * FROM Win32_OperatingSystem")

                    For Each queryObj As ManagementObject In searcher.Get()
                        Dim max_memory As Double = (queryObj("TotalVisibleMemorySize"))
                        Dim available_memory As Double = (queryObj("FreePhysicalMemory"))
                        my_memory = (1 - (available_memory / max_memory)) * 100
                    Next
                    my_memory_total(i) = my_memory
                Catch err As ManagementException
                    'Console.WriteLine("An error occurred while querying for WMI data: " & err.Message)
                End Try

                'On va rechercher la valeur de la charge du cpu

                Try
                    Dim searcher As New ManagementObjectSearcher( _
                        "root\CIMV2", _
                        "SELECT * FROM Win32_Processor")
                    For Each queryObj As ManagementObject In searcher.Get()
                        my_cpu_load = (queryObj("LoadPercentage"))
                        my_cpu_frequency_max = (queryObj("MaxClockSpeed"))
                        my_cpu_frequency_use = (queryObj("CurrentClockSpeed"))
                        my_cpu = ((my_cpu_load * my_cpu_frequency_use) / my_cpu_frequency_max)
                    Next
                    my_cpu_total(i) = my_cpu
                Catch err As ManagementException
                    'Console.WriteLine("An error occurred while querying for WMI data: " & err.Message)
                End Try
                Thread.Sleep(60000)

            Next i

            my_memory = ((my_memory_total(0) + my_memory_total(1) + my_memory_total(2) + my_memory_total(3) + my_memory_total(4)) / 5)
            my_cpu = ((my_cpu_total(0) + my_cpu_total(1) + my_cpu_total(2) + my_cpu_total(3) + my_cpu_total(4)) / 5)

            'On va rechercher la valeur du nom du serveur(ComputerName)

            Try
                Dim searcher As New ManagementObjectSearcher( _
                    "root\CIMV2", _
                    "SELECT * FROM Win32_OperatingSystem")
                For Each queryObj4 As ManagementObject In searcher.Get()
                    my_server = (queryObj4("CSName"))
                Next
            Catch err As ManagementException
                'Console.WriteLine("An error occurred while querying for WMI data: " & err.Message)
            End Try

            'On se connecte à la Db

            Try
                VDLB_VAR.Connect(SQL_server, SQL_userid, SQL_password, SQL_DATABASE)
            Catch ex As Exception
                'Console.WriteLine(ex.Message)
            End Try

            If (VDLB_VAR.ConnectionStatus) Then

                'On va rechercher la valeur de la mémoire physique disponible et la mémoire physique total, et on ressort le pourcentage utilisé par exemple 49

                Try                    VDLB_VAR.MySQL_Query("UPDATE vdlb_perf SET memory '" & my_memory & "' , cpu '" & my_cpu & "'   WHERE server='" + my_server + "'")
                    VDLB_VAR.CloseClass()
                Catch ex As Exception
                    'Console.WriteLine(ex.Message)
                End Try
            Else
                Console.WriteLine("Erreur SQL")
                Thread.Sleep(300000)
            End If

        Loop While boucle = "s"
    End Sub
End Class

Si qqun a une idée sur la chose ? car j'ai des codes fesant 10 x cette taille là et prenant même pas 700ko en mémoire.

Merci d'avance

11 réponses

jmfmarques Messages postés 7666 Date d'inscription samedi 5 novembre 2005 Statut Membre Dernière intervention 22 août 2014 27
8 mars 2008 à 09:43
Bonjour,


Je ne connais rien à VB.Net.


Par instinct, toutefois :


Je libèrerais Searcher avant d'en recréer un

Tu n'as pas quelquechose, sous VB.Net, comme Searcher.Dipose ... ou set Searcher = Nothing ... ou autre chose du genre ?
3
scottmat Messages postés 438 Date d'inscription samedi 24 mai 2003 Statut Membre Dernière intervention 23 janvier 2011 1
8 mars 2008 à 09:47
normalement non, mais bon tu peut l'optimiser en le déclarant qu'une fois.

et pour liberer la mémoire c'est bien dispose jmfmarques ;)
3
cs_casy Messages postés 7741 Date d'inscription mercredi 1 septembre 2004 Statut Membre Dernière intervention 24 septembre 2014 40
8 mars 2008 à 10:10
Problèmes d'objets créer et non détruit.

Pour commencer ceci :
            Dim i As Integer
            For i = 0 To 4
à chauqe tour de ta boucle Do, tu crée une variable i, qui ne te sert que dans la boucle For, la précédente n'étant pas forcément détruite. Utilise plutot ceci, ta variable i sera automatiquement marquée libérable à la fin de la boucle For
            For i As Integer = 0 To 4

Ensuite pour Searcher, tu crée les objets, mais jamais tu ne les détruits.
Essaye peut-etre d'encadrer ton code utilisant l'objet dans un Using, l'objet créé par le using étant automatiquement détruit à la fin du Using :

                   Using searcher As New ManagementObjectSearcher( _
                        "root\CIMV2", _
                        "SELECT * FROM Win32_Processor")
                    For Each queryObj As ManagementObject In searcher.Get()
                        my_cpu_load = (queryObj("LoadPercentage"))
                        my_cpu_frequency_max = (queryObj("MaxClockSpeed"))
                        my_cpu_frequency_use = (queryObj("CurrentClockSpeed"))
                        my_cpu = ((my_cpu_load * my_cpu_frequency_use) / my_cpu_frequency_max)
                    Next
                    my_cpu_total(i) = my_cpu
                    End Using

Si le using ne marche pas, mais simplement un searcher=Nothing juste avant le Catch

Rien que ça devrai, je pense amélioré un peu les choses.

Info : En .Net, la libération de la mémoire est à la charge du Garbage Collector. Elle n'est pas forcément instantanée.

---- Sevyc64  (alias Casy) ---- <hr size ="2" width="100%" /># LE PARTAGE EST NOTRE FORCE #    http://aide-office-vba.monforum.com/index.php
3
dimitriusai Messages postés 76 Date d'inscription lundi 6 novembre 2006 Statut Membre Dernière intervention 7 mai 2009 1
8 mars 2008 à 18:29
Merci bcp les gars, du code de vendredi soir !!! faut être indulgant.  Je test cela lundi au boulot.

++ etmerci à tous
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
laurent207 Messages postés 101 Date d'inscription jeudi 31 janvier 2002 Statut Membre Dernière intervention 11 avril 2008
31 mars 2008 à 13:08
bonjour,

J'ai le même problème que toi, mon appli qui tourne comme service windows augmante sans arrêt en mémoire.

Elle commence à 36Mo et augmante progressivement et constament. Alors j'ai lu sur des forum qu'une appli .net démarre en utilisant environ 30Mo. Donc, si la tienne prend que 20Mo c'est bien, mais augmente-t-elle en mémoire ?

laurent207
0
dimitriusai Messages postés 76 Date d'inscription lundi 6 novembre 2006 Statut Membre Dernière intervention 7 mai 2009 1
31 mars 2008 à 13:47
Après une optimisation, comme expliquée ci dessus, et surtt l'utilisation du garbage collector, j'ai réussi à stabiliser l'utilisation mémoire à 17mo, et le logiciel tourne depuis 3 semaines sans problème et augmentation en ram.
0
laurent207 Messages postés 101 Date d'inscription jeudi 31 janvier 2002 Statut Membre Dernière intervention 11 avril 2008
11 avril 2008 à 12:39
est-ce que je peux voir ton code, stp.

pour chaque objet (integer, string, ping, searcher, ldap ou autre), j'ai mit une .dispose et objet=nothing, dés que j'en ai plus bessoin. J'ai aussi fait un for i as integer, mais ça na pas l'air de marcher. Maintenant au lieu de monter à 600Mo, je monte à 70Mo au bout de 2 jours.

laurent207
0
dimitriusai Messages postés 76 Date d'inscription lundi 6 novembre 2006 Statut Membre Dernière intervention 7 mai 2009 1
11 avril 2008 à 12:42
Fait un appel au garbage collector comme expliqué au dessus.
à la fin de ta boucle
System.GC.Collect()

Déso mais le code est confidentiel vu l'utilité qu'il a
0
laurent207 Messages postés 101 Date d'inscription jeudi 31 janvier 2002 Statut Membre Dernière intervention 11 avril 2008
11 avril 2008 à 13:00
pardon, j'ai oublié de dire que j'ai mit ça aussi

System.GC.Collect()
System.GC.WaitForPendingFinalizers()

laurent207
0
dimitriusai Messages postés 76 Date d'inscription lundi 6 novembre 2006 Statut Membre Dernière intervention 7 mai 2009 1
11 avril 2008 à 13:01
Bizard,

dans quel cas utilise tu ton prog ?
met ton code et ou partie de ton code afin que je jette un coup d'oeil.
0
laurent207 Messages postés 101 Date d'inscription jeudi 31 janvier 2002 Statut Membre Dernière intervention 11 avril 2008
11 avril 2008 à 13:35
c'est une parti, y a environ 5000 lignes

    Private Sub Commencer()
        Dim str_AdresseIPDuPoste As String = String.Empty
        Dim str_NumDuPoste As String = String.Empty
        Dim b_Prioritaire As Boolean = False 'booléen pour forcer l'inventaire du poste
        Dim int_IDPoste As Integer = 0 'correspond à l'id du poste dans la bd
        Dim b_Ancien As Boolean = False 'booléen pour savoir si l'inventaire est ancien
        Dim b_Ping As Boolean = False
        Dim tab_ListOrdi() As String
        Dim int_NbOrdiRestant As Integer = 0
        Dim obj_DateLog As Date = System.DateTime.Today

        While True 'boucle infinie car le service tourne à l'infini ^^
            Dim int_NbPosteInventorie As Integer = 0
            tab_ListOrdi = Nothing

            Dim tab_ListOrdiTmp As New Collections.Generic.List(Of String)

            'AD(fw2)
            Dim Ldap As New DirectoryEntry("LDAP://nom_du_domaine_AD")
            'Création un filtre sur l'objet computer
            Dim searcher As DirectorySearcher = New DirectorySearcher(Ldap)
            searcher.Filter = "(objectCategory=Computer)"
            searcher.PageSize = 4000

            Try
                For Each result As SearchResult In searcher.FindAll
                    'on récuprer les noms des pc
                    Dim DirEntry As DirectoryEntry = result.GetDirectoryEntry
                    Dim nom As String = String.Empty

                    'nom = DirEntry.NativeObject.ToString
                    If Not (DirEntry.Properties("cn").Value Is Nothing) Then
                        nom = DirEntry.Properties("cn").Value.ToString()

                        'on redimensionne le tableau pour y insérer le poste trouvé dans AD
                        ReDim Preserve tab_ListOrdi(int_NbOrdiRestant)
                        tab_ListOrdi(int_NbOrdiRestant) = nom
                        int_NbOrdiRestant += 1
                    End If
                    DirEntry.Dispose()
                    DirEntry = Nothing
                    nom = Nothing
                Next result
            Catch ex As Exception
                str_Error = "37;" & str_NumDuPoste & ";erreur lors de la récupération de la liste des postes sur AD (" & ex.Message.ToString & ")"
                log.Fatal(str_Error)
                JEventLog.WriteEntry("Erreur lors de la récupération de la liste des postes sur AD (" & ex.Message.ToString & ")", EventLogEntryType.Warning)
                Thread.Sleep(1800000) '30mn
            End Try
            searcher.Dispose()
            searcher = Nothing
            Ldap.Close()
            Ldap.Dispose()
            Ldap = Nothing

            'affiche le nombre total de poste (voisinage réseau + AD)
            int_NbOrdiRestant = tab_ListOrdi.GetLength(0)
            str_Error = "99;" & str_NumDuPoste & ";nombre de postes trouvé : " & int_NbOrdiRestant.ToString

            'on parcourt le tableau (l'indice commence à 0, donc on enléve 1 au nombre total de poste)
            For i As Integer = 0 To int_NbOrdiRestant - 1
                BD.Connexion()
                Try
                    'recharge les paramètres du fichier de config XML car on peut les avoir modifiés
                    Nom_du_service.My.Settings.Reload()

                    str_AdresseIPDuPoste = tab_ListOrdi(i).ToString.Trim

                    'On récupère le num d'inventaire du poste à partir de son adresse IP
                    str_NumDuPoste = ""
                    str_NumDuPoste = RecupNum(str_AdresseIPDuPoste).Trim

                    'cherche si le nom du poste est dans la base de données
                    Dim b_Existe As Boolean = False                    b_Existe BD.Existe("SELECT * FROM Poste WHERE NumInventaire " & Chr(34) & str_NumDuPoste & Chr(34))

                    If (Not b_Existe) Then
                        'il n'existe pas dans la base de données
                        'on ping le poste
                        b_Ping = False
                        b_Ping = PingFW2(str_AdresseIPDuPoste)

                        If (b_Ping) Then
                            'pour pas dépasser la taille du champs dans access
                            str_NumDuPoste = Microsoft.VisualBasic.Left(str_NumDuPoste, 20)

                            BD.AjouterPoste("SELECT * FROM Poste", "NumInventaire", str_NumDuPoste, True)
                            BD.AjouterPoste("SELECT * FROM Poste WHERE NumInventaire = " & Chr(34) & str_NumDuPoste & Chr(34), "Prioritaire", "True", False)
                            BD.AjouterPoste("SELECT * FROM Poste WHERE NumInventaire = " & Chr(34) & str_NumDuPoste & Chr(34), "DateMajFiche", System.DateTime.Today.ToString, False)
                            b_Existe = True
                        End If
                    End If

                    If (b_Existe) Then
                        'Récupère le champs "IDPoste" de la table "Poste"                        int_IDPoste BD.ReturnID("SELECT * FROM Poste WHERE NumInventaire " & Chr(34) & str_NumDuPoste & Chr(34))

                        'Si l'inventorisation du poste est inférieur au cycle
                        Dim obj_Cycle As New TimeSpan(CInt(My.Settings.Cycle_inventaire), 0, 0, 0, 0)

                        If (CDate(BD.ReturnDate("SELECT * FROM Poste WHERE IDPoste = " & int_IDPoste)) < (System.DateTime.Today() - obj_Cycle)) Then
                            'l'inventaire du poste est ancien
                            b_Ancien = True
                        Else
                            'l'inventaire du poste n'est pas ancien
                            b_Ancien = False
                            'si prioritaire, on force l'inventaire                            b_Prioritaire BD.EstPrioritaire("SELECT * FROM Poste WHERE IDPoste " & int_IDPoste)
                            If (b_Prioritaire) Then
                                b_Ancien = True
                                'lbl_Forcer.Text = ""
                            End If
                        End If

                        obj_Cycle = Nothing

                        If (b_Ancien) Then
                            'on ping le poste
                            b_Ping = False
                            b_Ping = PingFW2(str_AdresseIPDuPoste)

                            If (b_Ping) Then
                                'on ajoute la date du ping
                                BD.AjouterPoste("SELECT * FROM Poste WHERE IDPoste = " & int_IDPoste, "DatePing", System.DateTime.Today.ToString, False)

                                'vérifie si le poste est au moins sous Windows 2000 et qu'on ai accés au c$

                                If (Poste2k(str_AdresseIPDuPoste)) Then
                                    'répare le WMI et execute un script vbs
                                    b_WMIOk = RepareWMI(str_AdresseIPDuPoste, str_NumDuPoste)

                                    If (Not b_WMIOk) Then
                                        'on essaye de récupérer le numèro de serie par DMI
                                        str_Error = "45;" & str_NumDuPoste & ";impossible de réparer WMI automatiquement (intervention manuel requise)"
                                        log.Warn(str_Error)
                                    End If

                                    'vérifi si on peut se connecter au registre distant
                                    Try
                                        Dim Ruche As RegistryKey = Nothing

                                        If (str_AdresseIPDuPoste = "localhost") Then
                                            Ruche = Registry.LocalMachine.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion")
                                        Else
                                            Ruche = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, str_AdresseIPDuPoste).OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion")
                                        End If

                                        If (Ruche.GetValue("ProductId") IsNot Nothing) Then
                                            b_ConnexionRegistre = True
                                        Else
                                            b_ConnexionRegistre = False
                                        End If

                                        If Ruche IsNot Nothing Then Ruche.Close()
                                        Ruche = Nothing
                                    Catch ex As Exception
                                        str_Error = "41;" & str_NumDuPoste & ";droits insuffisant pour se connecter à la base de registre (" & ex.Message.ToString & ")"
                                        b_ConnexionRegistre = False
                                    End Try

                                    If (b_ConnexionRegistre) Then
                                        'Inventaire_du_poste(str_AdresseIPDuPoste, str_NumDuPoste, int_IDPoste)
                                        BD.AjouterPoste("SELECT * FROM Poste WHERE IDPoste = " & int_IDPoste, "Prioritaire", "False", False)
                                        int_NbPosteInventorie = int_NbPosteInventorie + 1
                                    End If
                                End If
                            End If
                            b_Ping = Nothing
                        End If
                        b_Ancien = Nothing
                    End If
                    b_Existe = Nothing
                    int_IDPoste = Nothing
                    b_WMIOk = Nothing
                    b_ConnexionRegistre = Nothing
                Catch ex As Exception
                    str_Error = "37;" & str_NumDuPoste & ";erreur inconnue dans le module général c'est produite (" & ex.Message.ToString & ")"
                    Debug.Print(str_Error)
                End Try

                'affiche le nombre d'ordi restant
                If (int_NbOrdiRestant > 0) Then int_NbOrdiRestant = int_NbOrdiRestant - 1

                'ferme la connexion à la base de données et supprime les objets en mémoire
                BD.Deconnexion("olex_BD")

                str_AdresseIPDuPoste = Nothing
                str_NumDuPoste = Nothing
                b_Prioritaire = Nothing
                int_IDPoste = Nothing
                b_Ancien = Nothing
                b_Ping = Nothing
                b_ConnexionRegistre = Nothing
                b_WMIOk = Nothing
            Next i

            tab_ListOrdi = Nothing
            tab_ListOrdiTmp = Nothing
            int_NbOrdiRestant = Nothing
            int_NbPosteInventorie = Nothing
            ServiceController1.Refresh()
            System.GC.Collect()
            System.GC.WaitForPendingFinalizers()

            'vérification de la date à la fin de la boucle pour faire un traitemant journalier
            If (System.DateTime.Today > obj_DateLog) Then
                obj_DateLog = System.DateTime.Today
            End If
        End While
    End Sub

    Private Function PingFW2(ByVal str_AdresseIPDuPoste As String) As Boolean
        ' AdresseIP : chaîne de caractère contenant l'adresse IP de l'hôte à "pinger"
        Dim b_resultatPing As Boolean = False
        Dim PingOpt As New PingOptions(64, True)
        Dim bt_buffer As Byte = 0
        Dim obj_Ping As New Ping

        ' Objet PingReply qui nous permettra de récupérer le résultat
        Dim obj_ReponsePing As PingReply

        Try
            ' Instanciation d'un objet Ping
            ' Récupération du résultat obtenu par la méthode Send()
            obj_ReponsePing = obj_Ping.Send(str_AdresseIPDuPoste, 1000) ', bt_buffer, PingOpt)
            ' Formatage du résultat avec récupération du temps en millisecondes
            ' grâce à la propriété RoundtripTime.

            Select Case obj_ReponsePing.Status
                Case IPStatus.Success
                    b_resultatPing = True
                Case IPStatus.TimedOut
                    b_resultatPing = False
                Case Else
                    b_resultatPing = False
            End Select

        Catch ex As Exception
            str_Error = Chr(34) & "00" & Chr(34) & ";" & str_AdresseIPDuPoste & ";hôte inconnue " & (ex.Message)
            b_resultatPing = False
        Finally
            obj_Ping.Dispose()
            obj_ReponsePing = Nothing
        End Try

        bt_buffer = Nothing
        PingOpt = Nothing
        obj_Ping = Nothing

        Return b_resultatPing
        b_resultatPing = Nothing
    End Function

voici une fonction qui utilise du wmi :

        Public Shared Function Marque(ByVal str_AdresseIPDuPoste As String, ByVal str_NumDuPoste As String, ByVal int_IDPoste As Integer) As Boolean
            Dim b_Marque As Boolean = False
            Dim str_Manufacturer As String = String.Empty

            Try
                Dim searcher As New ManagementObjectSearcher("\" & str_AdresseIPDuPoste & "\root\CIMV2", "SELECT * FROM Win32_ComputerSystem")
                Dim info As ManagementObject = Nothing

                For Each info In searcher.Get()
                    str_Manufacturer = info("Manufacturer").ToString

                    'pour pas dépasser la taille du champs dans access
                    str_Manufacturer = Microsoft.VisualBasic.Left(str_Manufacturer, 60)

                    BD.AjouterRow("SELECT * FROM Poste WHERE IDPoste = " & int_IDPoste, "Poste", "Marque", str_Manufacturer, int_IDPoste, False)
                Next

                b_Marque = True

                info.Dispose()
                info = Nothing
                searcher.Dispose()
                searcher = Nothing
            Catch ex As Exception
                str_Error = "11;" & str_NumDuPoste & ";erreur WMI (Materiel.Marque)"
                b_Marque = False
            End Try

            str_Manufacturer = Nothing

            Return b_Marque
            b_Marque = Nothing
        End Function

laurent207
0
Rejoignez-nous