TwinCAT ADS in C# Applikation frisst den Arbeitsspeicher auf

sparx

Member
Beiträge
8
Punkte Reaktionen
0
Zuviel Werbung?
->Hier kostenlos registrieren
Hallo

Ich habe ein Programm in C# mit WPF Oberfläche geschrieben welches im Hintergrund mit der "TwinCAT.Ads.dll" von Beckhoff arbeitet.

Zur abfrage meiner Variablen nutze ich die DeviceNotification Funktion, in der ich das Zeitlimit für das Abfragen auf 250 ms gestellt habe.
Zu überwachen sind 26 Variablen vom Typ BOOL, DINT oder LREAL (insgesamt 93 Bytes).


Code:
private int Zyklus_VarRefresh = 250;    //Zykluszeit zum Erneuern der SPS Werte

private TcAdsClient tcClient; //ADS Client

private static AdsStream adsreaderStream = new AdsStream(93); //ADS Stream zum Zyklischen Abfragen aller Variablen
private static BinaryReader binReader = new BinaryReader(adsreaderStream); //Reader für ADS Stream zum Zyklischen Abfragen aller Variablen

...

Handle_GlobalVar1 = tcClient.AddDeviceNotification(".GlobalVar1", adsreaderStream, 0, 4, AdsTransMode.OnChange, Zyklus_VarRefresh, 0, DBNull.Value); //4 Bytes
Handle_GlobalVar2 = tcClient.AddDeviceNotification(".GlobalVar2", adsreaderStream, 4, 4, AdsTransMode.OnChange, Zyklus_VarRefresh, 0, DBNull.Value); //4 Bytes
...

tcClient.Synchronize = true;
tcClient.AdsNotification += new AdsNotificationEventHandler(tcClient_AdsNotification);

Ändert sich ein Variablenwert wird das Event aufgerufen:

Code:
void tcClient_AdsNotification(object sender, AdsNotificationEventArgs e)
{
        e.DataStream.Position = e.Offset;

        switch (e.NotificationHandle)
        {
            //GlobalVar1
            case 1: 
                ...


Dies funktioniert eigendlich ganz gut.... bis das Programm irgendwann abstürtzt weil es mehr wie 1 GB Arbeitsspeicher reserviert hat :shock:

Ist eine Verbindung aufgebaut, werden in meinem Code keine neuen Variablen Deklariert, kein Array gefüllt usw.
Trotzdem steigt der Speicher stetig an.

Die einzige alternative die mir einfällt ist jede Variable einzeln zu pollen.

Kennt jemand das Problem oder hat einen Tipp was ich da machen kann.


Gruß
Stefan
 

Neals

Well-known member
Beiträge
340
Punkte Reaktionen
71
Code:
void tcClient_AdsNotification(object sender, AdsNotificationEventArgs e) {
         e.DataStream.Position = e.Offset;
          switch (e.NotificationHandle)
         {
             //GlobalVar1
             case [U][B]Handle_GlobalVar1[/B][/U]:
                  ...

Müsste hier in der Case-Anweisung nicht das Handle abgefragt werden?

Ich habe auch schon häufig Notifications genutzt, aber nie eine solche Speicherauslastung bemerkt.
Derzeit kann ich im Code jedoch keinen groben Fehler erkennen. Nach welcher Zeit tritt denn der Absturz auf?
Könntest du eventuell noch den restlichen Code vom Notification-Handler (tcClient_AdsNotification) posten?
 
OP
S

sparx

Member
Beiträge
8
Punkte Reaktionen
0
Zuviel Werbung?
->Hier kostenlos registrieren
Ja das Handle muss abgefragt werden.
In C# werden bei switch case nur Konstante Werte zugelassen. Bei Visual Basic gibt es select case wo als Sprungmarke eine Variable erlaubt ist.
Ich könnte das switch duch mehrere if Anweisungen ersetzen in denen ich die "Handle_*" Variablen abfrage.
Da ich aber die Reihenfolge weiß in denen ich die Variablen für das Event registriere, kann ich da mit festen Nummern arbeiten.

Ich habe jetzt einfach mal die ganze Methode kopiert.
Im Beispiel meines letzten Posts habe ich die Ersten Vaiablen vom Namen angepasst, also nicht wundern.

Das Programm in dem ich diesen Code nutze soll mehrere Tage durchlaufen. Nach 2 - 3 Tagen laufzeit ist der Verwendete Arbeitsspeicher bei 1GB!
Könnte es vieleicht sein das 250ms abfragezeit zu schnell ist?

Code:
 void tcClient_AdsNotification(object sender, AdsNotificationEventArgs e)
        {
            e.DataStream.Position = e.Offset;

            switch (e.NotificationHandle)
            {
                //SPS_Temp_Kanal1
                case 1: 
                    SPS_Temp_Kanal1 = binReader.ReadInt32();

                    if (SPS_Temp_Kanal1 > 80000)
                    {
                        //Wenn Temperatur größer 800°C -> Kein Messelement angeschlossen
                        tb_sps_temp_knl1.Text = "----------";
                    }
                    else
                    {
                        //Temperaturwert durch 100 Teilen und anzeigen
                        tb_sps_temp_knl1.Text = (Convert.ToDouble(SPS_Temp_Kanal1.ToString()) / 100).ToString();
                    }
                    break;

                //SPS_Temp_Kanal2
                case 2:
                    SPS_Temp_Kanal2 = binReader.ReadInt32();

                    if (SPS_Temp_Kanal2 > 80000)
                    {
                        //Wenn Temperatur größer 800°C -> Kein Messelement angeschlossen
                        tb_sps_temp_knl2.Text = "----------";
                    }
                    else
                    {
                        //Temperaturwert durch 100 Teilen und anzeigen
                        tb_sps_temp_knl2.Text = (Convert.ToDouble(SPS_Temp_Kanal2.ToString()) / 100).ToString();
                    }
                    break;

                //SPS_Temp_Kanal3
                case 3:
                    SPS_Temp_Kanal3 = binReader.ReadInt32();

                    if (SPS_Temp_Kanal3 > 80000)
                    {
                        //Wenn Temperatur größer 800°C -> Kein Messelement angeschlossen
                        tb_sps_temp_knl3.Text = "----------";
                    }
                    else
                    {
                        //Temperaturwert durch 100 Teilen und anzeigen
                        tb_sps_temp_knl3.Text = (Convert.ToDouble(SPS_Temp_Kanal3.ToString()) / 100).ToString();
                    }
                    break;

                //SPS_Temp_Kanal4
                case 4:
                    SPS_Temp_Kanal4 = binReader.ReadInt32();

                    if (SPS_Temp_Kanal4 > 80000)
                    {
                        //Wenn Temperatur größer 800°C -> Kein Messelement angeschlossen
                        tb_sps_temp_knl4.Text = "----------";
                    }
                    else
                    {
                        //Temperaturwert durch 100 Teilen und anzeigen
                        tb_sps_temp_knl4.Text = (Convert.ToDouble(SPS_Temp_Kanal4.ToString()) / 100).ToString();
                    }
                    break;

                //SPS_Servo_Betr_Winkel_IST
                case 5:
                    SPS_Servo_Betr_Winkel_IST = binReader.ReadDouble();

                    //Wert Negieren und mit 3 Nachkommastellen anzeigen
                    tb_sps_servo_betr_w_ist.Text = (SPS_Servo_Betr_Winkel_IST * -1).ToString("0.000");
                    break;

                //SPS_Servo_Betr_Winkel_SOLL
                case 6:
                    SPS_Servo_Betr_Winkel_SOLL = binReader.ReadDouble();

                    //Wenn das Programm nicht im Handmodus ist auch die SollWerte anzeigen (Keine Manuelle Sollwerteingabe)
                    if (Programmstatus != Progstatus.Hand_Modus)
                    {
                        //Wert Negieren und mit 3 Nachkommastellen anzeigen
                        tb_sps_servo_betr_w_soll.Text = (SPS_Servo_Betr_Winkel_SOLL * -1).ToString("0.000");
                    }
                    break;

                //SPS_Servo_Temp_Winkel_IST
                case 7:
                    SPS_Servo_Temp_Winkel_IST = binReader.ReadDouble();

                    //Wert Negieren und mit 3 Nachkommastellen anzeigen
                    tb_sps_servo_temp_w_ist.Text = (SPS_Servo_Temp_Winkel_IST * -1).ToString("0.000");
                    break;

                //SPS_Servo_Temp_Winkel_SOLL
                case 8:
                    SPS_Servo_Temp_Winkel_SOLL = binReader.ReadDouble();

                    //Wenn das Programm nicht im Handmodus ist auch die SollWerte anzeigen (Keine Manuelle Sollwerteingabe)
                    if (Programmstatus != Progstatus.Hand_Modus)
                    {
                        //Wert Negieren und mit 3 Nachkommastellen anzeigen
                        tb_sps_servo_temp_w_soll.Text = (SPS_Servo_Temp_Winkel_SOLL * -1).ToString("0.000");
                    }
                    break;

                //SPS_Servo_Tuer_offen_IST
                case 9:
                    SPS_Servo_Tuer_offen_IST = binReader.ReadBoolean();

                    cb_sps_servo_tuer_auf_ist.IsChecked = SPS_Servo_Tuer_offen_IST;
                    break;

                //SPS_Servo_Tuer_geschlossen_IST
                case 10:
                    SPS_Servo_Tuer_geschlossen_IST = binReader.ReadBoolean();

                    cb_sps_servo_tuer_zu_ist.IsChecked = SPS_Servo_Tuer_geschlossen_IST;
                    break;
 
OP
S

sparx

Member
Beiträge
8
Punkte Reaktionen
0
Teil 2 des Codes:

Code:
 //SPS_Servo_Tuer_offen_SOLL
                case 11:
                    SPS_Servo_Tuer_offen_SOLL = binReader.ReadBoolean();

                    cb_sps_servo_tuer_auf_soll.IsChecked = SPS_Servo_Tuer_offen_SOLL;
                    break;

                //SPS_Servo_Tuer_geschlossen_SOLL
                case 12:
                    SPS_Servo_Tuer_geschlossen_SOLL = binReader.ReadBoolean();

                    cb_sps_servo_tuer_zu_soll.IsChecked = SPS_Servo_Tuer_geschlossen_SOLL;
                    break;

                //SPS_Schuetz_Steckdose_EIN
                case 13:
                    SPS_Schuetz_Steckdose_EIN = binReader.ReadBoolean();

                    cb_steckdose_ein.IsChecked = SPS_Schuetz_Steckdose_EIN;
                    break;

                //SPS_Schuetz_Pruefling_EIN
                case 14:
                    SPS_Schuetz_Pruefling_EIN = binReader.ReadBoolean();

                    cb_geraet_ein.IsChecked = SPS_Schuetz_Pruefling_EIN;
                    break;

                //SPS_L1_V
                case 15:
                    SPS_L1_V = binReader.ReadInt32();

                    //Gemessene Spannung mit Faktor 0,0001 multiplizieren und Wert mit einer Nachkommastelle anzeigen
                    //Minuswerte nicht anzeigen (Messfehler bei offenem Kontakt)
                    if (SPS_L1_V < 0)
                    {
                        tb_l1_v.Text = "0,0";
                    }
                    else
                    {
                        tb_l1_v.Text = (Convert.ToDouble(SPS_L1_V.ToString()) * 0.0001).ToString("0.0");
                    }
                    break;

                //SPS_L1_A
                case 16:
                    SPS_L1_A = binReader.ReadInt32();

                    //Gemessenen Strom mit Faktor 0,000001 multiplizieren und Wert mit einer Nachkommastelle anzeigen
                     //Minuswerte nicht anzeigen (Messfehler bei offenem Kontakt)
                    if (SPS_L1_A < 0)
                    {
                        tb_l1_a.Text = "0,0";
                    }
                    else
                    {
                        tb_l1_a.Text = (Convert.ToDouble(SPS_L1_A.ToString()) * 0.000001 * 30).ToString("0.0");
                    }
                    break;

                //SPS_L1_W
                case 17:
                    SPS_L1_W = binReader.ReadInt32();

                    //Gemessene Leistung mit Faktor 0,01 multiplizieren und Wert mit einer Nachkommastelle anzeigen
                    //Minuswerte nicht anzeigen (Messfehler bei offenem Kontakt)
                    if (SPS_L1_W < 0)
                    {
                        tb_l1_w.Text = "0,0";
                    }
                    else
                    {
                        tb_l1_w.Text = (Convert.ToDouble(SPS_L1_W.ToString()) * 0.01 * 30).ToString("0.0");
                    }
                    break;

                //SPS_L2_V
                case 18:
                    SPS_L2_V = binReader.ReadInt32();

                    //Gemessene Spannung mit Faktor 0,0001 multiplizieren und Wert mit einer Nachkommastelle anzeigen
                    //Minuswerte nicht anzeigen (Messfehler bei offenem Kontakt)
                    if (SPS_L2_V < 0)
                    {
                        tb_l2_v.Text = "0,0";
                    }
                    else
                    {
                        tb_l2_v.Text = (Convert.ToDouble(SPS_L2_V.ToString()) * 0.0001).ToString("0.0");
                    }
                    break;

                //SPS_L2_A
                case 19:
                    SPS_L2_A = binReader.ReadInt32();

                    //Gemessenen Strom mit Faktor 0,000001 multiplizieren und Wert mit einer Nachkommastelle anzeigen
                    //Minuswerte nicht anzeigen (Messfehler bei offenem Kontakt)
                    if (SPS_L2_A < 0)
                    {
                        tb_l2_a.Text = "0,0";
                    }
                    else
                    {
                        tb_l2_a.Text = (Convert.ToDouble(SPS_L2_A.ToString()) * 0.000001 * 30).ToString("0.0");
                    }
                    break;

                //SPS_L2_W
                case 20:
                    SPS_L2_W = binReader.ReadInt32();

                    //Gemessene Leistung mit Faktor 0,01 multiplizieren und Wert mit einer Nachkommastelle anzeigen
                    //Minuswerte nicht anzeigen (Messfehler bei offenem Kontakt)
                    if (SPS_L2_W < 0)
                    {
                        tb_l2_w.Text = "0,0";
                    }
                    else
                    {
                        tb_l2_w.Text = (Convert.ToDouble(SPS_L2_W.ToString()) * 0.01 * 30).ToString("0.0");
                    }
                    break;

                //SPS_L3_V
                case 21:
                    SPS_L3_V = binReader.ReadInt32();

                    //Gemessene Spannung mit Faktor 0,0001 multiplizieren und Wert mit einer Nachkommastelle anzeigen
                    //Minuswerte nicht anzeigen (Messfehler bei offenem Kontakt)
                    if (SPS_L3_V < 0)
                    {
                        tb_l3_v.Text = "0,0";
                    }
                    else
                    {
                        tb_l3_v.Text = (Convert.ToDouble(SPS_L3_V.ToString()) * 0.0001).ToString("0.0");
                    }
                    break;

                //SPS_L3_A
                case 22:
                    SPS_L3_A = binReader.ReadInt32();

                    //Gemessenen Strom mit Faktor 0,000001 multiplizieren und Wert mit einer Nachkommastelle anzeigen
                     //Minuswerte nicht anzeigen (Messfehler bei offenem Kontakt)
                    if (SPS_L3_A < 0)
                    {
                        tb_l3_a.Text = "0,0";
                    }
                    else
                    {
                        tb_l3_a.Text = (Convert.ToDouble(SPS_L3_A.ToString()) * 0.000001 * 30).ToString("0.0");
                    }
                    break;

                //SPS_L3_W
                case 23:
                    SPS_L3_W = binReader.ReadInt32();

                    //Gemessene Leistung mit Faktor 0,01 multiplizieren und Wert mit einer Nachkommastelle anzeigen
                     //Minuswerte nicht anzeigen (Messfehler bei offenem Kontakt)
                    if (SPS_L3_W < 0)
                    {
                        tb_l3_w.Text = "0,0";
                    }
                    else
                    {
                        tb_l3_w.Text = (Convert.ToDouble(SPS_L3_W.ToString()) * 0.01 * 30).ToString("0.0");
                    }
                    break;

                //SPS_Handbetrieb
                case 24:
                    SPS_Handbetrieb = binReader.ReadBoolean();
                    break;

                //SPS_Automatikbetrieb
                case 25:
                    SPS_Automatikbetrieb = binReader.ReadBoolean();
                    break;

                //SPS_Merker_Fehler_SPS
                case 26:
                    SPS_Merker_Fehler_SPS = binReader.ReadBoolean();
                    break;
            }
        }
 
Oben