Optimiser du code prennant beacoup trop de mémoire VB.NET [Résolu]

dimitriusai 76 Messages postés lundi 6 novembre 2006Date d'inscription 7 mai 2009 Dernière intervention - 8 mars 2008 à 08:21 - Dernière réponse : laurent207 101 Messages postés jeudi 31 janvier 2002Date d'inscription 11 avril 2008 Dernière intervention
- 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
Afficher la suite 

Votre réponse

11 réponses

jmfmarques 7668 Messages postés samedi 5 novembre 2005Date d'inscription 22 août 2014 Dernière intervention - 8 mars 2008 à 09:43
+3
Utile
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 ?
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de jmfmarques
scottmat 440 Messages postés samedi 24 mai 2003Date d'inscription 23 janvier 2011 Dernière intervention - 8 mars 2008 à 09:47
+3
Utile
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 ;)
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de scottmat
cs_casy 7745 Messages postés mercredi 1 septembre 2004Date d'inscription 24 septembre 2014 Dernière intervention - 8 mars 2008 à 10:10
+3
Utile
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
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de cs_casy
dimitriusai 76 Messages postés lundi 6 novembre 2006Date d'inscription 7 mai 2009 Dernière intervention - 8 mars 2008 à 18:29
0
Utile
Merci bcp les gars, du code de vendredi soir !!! faut être indulgant.  Je test cela lundi au boulot.

++ etmerci à tous
Commenter la réponse de dimitriusai
laurent207 101 Messages postés jeudi 31 janvier 2002Date d'inscription 11 avril 2008 Dernière intervention - 31 mars 2008 à 13:08
0
Utile
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
Commenter la réponse de laurent207
dimitriusai 76 Messages postés lundi 6 novembre 2006Date d'inscription 7 mai 2009 Dernière intervention - 31 mars 2008 à 13:47
0
Utile
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.
Commenter la réponse de dimitriusai
laurent207 101 Messages postés jeudi 31 janvier 2002Date d'inscription 11 avril 2008 Dernière intervention - 11 avril 2008 à 12:39
0
Utile
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
Commenter la réponse de laurent207
dimitriusai 76 Messages postés lundi 6 novembre 2006Date d'inscription 7 mai 2009 Dernière intervention - 11 avril 2008 à 12:42
0
Utile
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
Commenter la réponse de dimitriusai
laurent207 101 Messages postés jeudi 31 janvier 2002Date d'inscription 11 avril 2008 Dernière intervention - 11 avril 2008 à 13:00
0
Utile
pardon, j'ai oublié de dire que j'ai mit ça aussi

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

laurent207
Commenter la réponse de laurent207
dimitriusai 76 Messages postés lundi 6 novembre 2006Date d'inscription 7 mai 2009 Dernière intervention - 11 avril 2008 à 13:01
0
Utile
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.
Commenter la réponse de dimitriusai
laurent207 101 Messages postés jeudi 31 janvier 2002Date d'inscription 11 avril 2008 Dernière intervention - 11 avril 2008 à 13:35
0
Utile
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
Commenter la réponse de laurent207

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.