| 

.NET C# Java Javascript Exception

4
Hallo,

ich habe seit einigen Tagen folgendes Phänomen:
Mein Programm belegt beim Starten so ca. 35 MB Speicher. Über das Menustrip kann man ein Formular (heißt hier einfach mal Form2) öffnen, das viele Daten anzeigt und dementsprechend knackig viele Controls hat: so ca. 300 Textboxen und 250 Labels - verteilt auf verschiedene Panels in einem Tabcontrol. Dass das Formular beim Öffnen natürlich 3-4 Sekunden braucht(e), ist logisch und auch nicht so schlimm in dem Moment.

Auf meinem Rechner mit dem VB2010EE läuft alles nach wie vor ohne Probleme, sowohl im Debug- als auch im Releasemodus. Verwende ich das Programm auf einem anderen Rechner, verzögert sich der Start des Form2 teilweise auf 5 Minuten und im Taskmanager kann ich beobachten, dass sich das Programm bis zu fürstlichen 1,3 GB Speicher schnappt und in dem Moment, in dem das Formular angezeigt wird, fällt der Verbrauch mit einem Schlag wieder auf ungefähr dem vorherigen Wert.
Da ich an dem Formular mit Code schon ewig nichts mehr geändert habe, stehe ich vor einem Rätsel, wo dieses merkwürdige Verhalten her kommt resp. wie ich das beheben kann.

Ich habe schon auf den letzte Dim-Befehl, der per New arbeitet, einen Haltepunkt gesetzt. Wenn ich dann im Einzelschritt weiter gehe, erscheint im Ausgabefenster tonnenweise
"Einzelschritt: Nichtbenutzercode "programm.Form2.controlX" wird übersprungen." (hier jeweils die Controls hinter Form2)
"Einzelschritt: Nichtbenutzercode "programm.Form2.InitializeComponent" wird übersprungen."

Ich hoffe, mein Problem ist klar und hoffe noch mehr, dass mir jemand helfen kann!

P.S.: dieser uralte Post hat mir überhaupt nicht geholfen: http://codekicker.de/fragen/VB.NET-Form-mit-vielen-Controls-lagt/529
News:
08.01.2014
muffi 1,4k 1 9
Ist der andere Rechner 64-Bit und hast Du .NET Framework 4.5.1 installiert? Ich habe das Problem auch gehabt, aber nur im Releasemodus. Im Debug Modus lief es ok.
Tosch 09.01.2014
Habe mal in der Registry nachgesehen: .Net 4.0 ist installiert, aber Win7 64 Bit. Und wie Du schreibst, im Debug marschiert es, aber im Release nicht.
muffi 09.01.2014
Wenn ich mein Programm im Debugmode compiliert habe, lief es einwandfrei. Wurde es im Releasemode compiliert, lief es seeeehr langsam.
Framework: ich würde mal in der Systemsteuerung unter Programme und Funktionen nachschauen, was installiert ist. In Registry ist etwas schwierig zu sehen, welche Version genau installiert ist.
Tosch 09.01.2014
Also eine Lösung habe ich leider auch nicht gefunden. Habe ein paar Ansätze in Google gefunden, haben aber alle nichts gebracht.
Tosch 09.01.2014
Japp, es ist genau das Gleiche. .Net 4.5.1 ist installiert. Übrigens: Release-Modus funktioniert hier auch ohne Probleme, solange ich aus VB raus mit F5 starte. Sobald ich das Release sozusagen standalone starte (damit fällt der vshost-Prozess auch weg), ist das Problem. Mir würde es schon reichen, wenn ich wüsste, was genau fast 3 Minuten braucht (siehe dazu meine Kommentare in der Antwort unten, da Kommentar Nr. 3 - zumindest im Moment ist er Nr. 3).
Ich habe es auch schon als X86 kompiliert, der Effekt bleibt aber der Gleiche. Google hat genau wie bei Dir auch nichts Vernünftiges gebracht.
muffi 09.01.2014
Was mir inzwischen aufgefallen ist, vielleicht ist das bei Dir auch so: wenn man das Formular schließt (per Code disposed und öffnet es wieder (ohne das Mainform zu schließen), dann geht es schnell.
muffi 10.01.2014
4 Antworten
1
Ich habe bei MS einen Bug gemeldet und diese Antwort bekommen:

Try adding the [MethodImpl(MethodImplOptions.NoOptimization)] attribute before ‘InitializeComponent’ according to similar issue: https://connect.microsoft.com/VisualStudio/feedback/details/780437

Und es funktioniert tatsächlich.
15.01.2014
Tosch 216 5
Sehr, sehr geil! Also DAS ist definitiv den grünen Haken wert!
muffi 15.01.2014
1
Ich würde an deiner Stelle grundsätzlich über das Design der Maske nachdenken. Der zweiten Antwort in dem von dir zitierten Posting kann ich nur zustimmen.

Wenn es gute Gründe gibt, dass das Formular so gestaltet ist könnte es möglicherweise etwas bringen, wenn du die Daten verzögert lädst bzw. die Datenbindung verzögert durchführst. Damit meine ich, dass du zunächst nur die Daten, die im aktiven Tab angezeigt werden lädst und die restlichen Daten erst dann, wenn der Anwender den Tab auswählt. Das erfordert ztwar etwas mehr Logik beim Tab-Wechsel, sollte aber die Performance drastisch erhöhen.
09.01.2014
luedi 2,0k 1 9
Das Interessante an der Geschichte ist ja, dass beim Öffnen des Formulars noch überhaupt nichts passiert - selbst die Panels im Tabcontrol sind noch unsichtbar geschalten und werden erst bei Gebrauch sichtbar gemacht.
Möglicherweise habe ich im VB auch unbewusst irgend eine Compilereinstellung geändert (am Ende noch mit irgend einer dämlichen Tastenkombination). Ich kann mir absolut nicht erklären, warum ein Formular, an dem ich seit Wochen nichts mehr geändert habe (weder Design noch Code), auf einmal spinnt.
muffi 09.01.2014
Mir sind keine Einstellungen bekannt, welche die Performance beim Laden von Formularen beeinflussen. Ich habe eigentlich immer das gegenteilige Problem, dass das Laden beim Debuggen in der Entwicklungsumgebung länger dauert. Benutzt du irgendwelche Controls von Drittanbietern und wenn ja, hast du diese vielleicht aktualisiert?
luedi 09.01.2014
Das Formular nebst Code habe ich sehr lange nicht mehr geändert, auch keine Updates der Controls gemacht. Ich habe mich natürlich noch etwas auf die Suche begeben, ich habe noch ein Formular, das unzählige Controls enthält (aber nicht ganz so viele), das verhält sich ganz normal: Startzeit so ca. 2-3 Sekunden. Und bei meinem "Problemformular" war das eigentlich auch so gewesen. Mittlerweise war ich so frech und habe in der designer.vb eine StopWatch im InitializeComponents() eingebaut. Laufzeit: 500 ms, da bin ich gut bedient. Startzeit des Formulars: 3 min. Wie finde ich den Zeitfresser?
muffi 09.01.2014
Ich kann nur vermuten, da ich den Code nicht einsehen kann: Eine mögliche Ursache könnte sein, dass irgendetwas den UI-Thread blockiert, Ich hatte schonmal ein ähnliches Problem, das letztendlich darauf zurückzuführen war, dass sich zwei Threads blockiert haben, weil es durch die unterschiedliche Performance von zwei PC's zu einer Race-Condition kam. Im Zweifel solltest du ein Logging einbauen (am besten am Anfang und Ende jeder Methode eine Ausgabe), dann siehst du ja, wo es hängt.
luedi 10.01.2014
An Logging habe ich zwar schon gedacht, aber meine bescheidenen Kenntnisse vom VB2010EE reichen da nicht wirklich aus, wie ich das ein- bzw. ausschalten kann. Am Besten wäre es doch, möglichst die eine Anweisung zu loggen, in der das Problem überhaupt entsteht, oder sehe ich das falsch?
Dim frm_form2 as New formular
muffi 10.01.2014
Suche nach einem .Net Profiler, vielleicht hilft der dir dabei das Problem einzugrenzen/aufzudecken. Ob es den Eqatec Profiler noch gibt weiß ich nicht...
cybere 11.01.2014
1
Ich schreibe das folgende als Antwort auf deinen letzten Kommentar, weil die Kommentare auf 600 Zeichen begrenzt sind.

Es gibt ja diverse Logging-Frameworks wie Log4Net oder NLog, mit denen man relativ einfach Logging implementieren kann.

Um herauszufinden, welche Anweisung im Code die Probleme verursacht, musst du schon den ganzen Ladevorgang beobachten. Zum eine ist dies InitializeComponent (wo die Controls instanziiert werden) und zum anderen die diversen Events, welche beim Laden des Formulars ausgelöst werden (wie z.B. Form_Load oder diverse Changed-Events, die ausgelöst werden, wenn Daten an Controls wie z.B. Checkboxen oder Listbnoxen gebunden werden). Je nachdem, wie die Logik implementiert ist, kann dies zu fiesen und schwer zu debuggenden Performance-Problemen kommen. Ich musste mal eine alte VB6-Anwendung nach VB.NET migrieren. In dieser Anwendung wurden die Daten "manuell" (durch zuweisen an die entsprechende Property im Code) and die Controls gebunden. Die führte dazu, dass z.B. CheckBox_Changed Events beim Laden ausgeführt wurden. Der Code innerhalb des Events führte dazu, eine ganze Kaskade von Events ausgelost wurde und einige Events mehrfach ausgelöst wurden. In der Folge wurde die Initialisierung der Formulare teilweise bis zu 5x durchgeführt. Nachdem ich dafür gesorgt hatte, dass Events erst dann ausgelöst werden, wenn das Formular am Bildschirm angezeigt wird, war die Anwendung schnell. Das fiese an der Sache war, dass das ganze auch mit der generellen Performance des Rechners zu tun hatte und die Anwendung sich innerhalb der Entwicklungsumgebung im Debugger anders verhielt als wenn die exe direkt aufgerufen wurde.
11.01.2014
luedi 2,0k 1 9
Danke für Deinen Post, insbesondere die erste Hälfte dürfte für mich relevant sein. Da ich nicht weiß, ob man +1 und im Zweifelsfall "den grünen Haken" machen kann, mach ich erst mal weder noch (+1 ist es aber auf jeden Fall).
Was Du am Ende schreibst, ist genau das, was bei mir auch klemmt (nur, dass es nicht von VB6 migriert ist, sondern von VB2005 nach VB2010). Im Debug-Modus läuft's ohne Probleme, aber wehe, man lässt die Release-exe laufen...
muffi 13.01.2014
Ohne Loggingtool habe ich inzwischen herausgefunden, dass z. B. Schleifen wie diese EWIG brauchen und wohl für den massiven Speicherverbrauch verantwortlich sind:
For Each c As Control In Panel1.Controls
If (TypeOf c Is TextBox) Or (TypeOf c Is RichTextBox) Or (TypeOf c Is BorderedTextBox) Then
c.Text = ""
End If
Next
Es gibt insgesamt 13 derartige Panels. Wie könnte ich das besser hinbekommen?
muffi 13.01.2014
0
Ohne Loggingtool habe ich inzwischen herausgefunden, dass z. B. Schleifen wie diese EWIG brauchen und wohl für den massiven Speicherverbrauch verantwortlich sind:
For Each c As Control In Panel1.Controls
If (TypeOf c Is TextBox) Or (TypeOf c Is RichTextBox) Or (TypeOf c Is BorderedTextBox) Then
c.Text = ""
End If
Next
Es gibt insgesamt 13 derartige Panels. Wie könnte ich das besser hinbekommen?


Du überprüfst jedes Control drei mal ob es einem bestimmten Typ entspricht. Ich weiß nicht wieviel Zeit das wirklich benötigt aber einmal
pseudo code: var controlType = TypeOf c
ist sicher billiger...

Generell würd ich sagen lade alle Controlls die deinen Kriterien entsprechen in eine Liste und arbeite dann aus dieser Liste weiter.

pseudo code:

List <Control> passendeControls = GetPassendeControls(Panel1);
passendeControls.Append(GetPassendeControls(Panel2);
...
passendeControls.ForEach(x => x.Text = string.Empty);

GetPassendeControls(...):
var controls = panel.Controls.Where(x => x.IsOfType(TextBox).ToList();
controls.Append(panel.Controls.Where(x => x.IsOfType(WhatEverTextBox).ToList();
...

Ist auch lesbarer/wartbarer.

Wie immer das auch in VB aussieht...

hth Ernst
13.01.2014
cybere 353 9
Habe ich getestet, sogar mittels LINQ, aber das hat keine Verbesserung gebracht. Das Problem scheinen die Panels zu sein. Testweise ein Panel (eines, nicht alle!) entfernt und die ganzen Textboxen direkt in die TabPage geschrieben, marschiert akzeptabel schnell. Kann das unter Umständen möglich sein, dass genau das eine Panel einen Schlag (welcher Art auch immer) abhatte, was das merkwürdige Verhalten verursacht hat?
muffi 13.01.2014
Vielleicht eine Redraw-Einstellung? Nicht, dass sich das gesamte Panel mit x textboxen neuzeichnet, nur weil Du bei einer Textbox den Text veränderst...

Übrigens solltest Du in dem o.a. Code bei Dir mir OrElse arbeiten. Zudem noch wie bereits vorgeschlagen, den Typ vorher einmal ermitteln.
Jens Duczmal 13.01.2014
@Jens: gute Idee, ich werde das morgen mal mit SuspendLayout und ResumeLayout probieren, glaube aber nicht, dass es daran liegt. Denn das ursprüngliche Problem entsteht ja irgendwo in der Nähe vom Instanziieren des Formulars. Die Textboxen werden erst nach einem Button-Click durchgenudelt. Was aber nicht heißt, dass der Compiler hier unter Umständen zu fleißig beim Optimieren sein könnte ;-)
muffi 13.01.2014
Also ich hab ein ganz simples Beispiel gemacht.
Ein Form mit Tabcontrol mit 3 Tabs und je 60 Labels und 60 Textboxen.
Läuft es auf einem 64-Bit System in Debug Mode (nicht in VS) geht das so um 300 Milisekunden. In Release Mode geht das aber ungefähr 15 Sekunden.
Das Form hat nur die Controls, absolut keinen Code.

Ich habe die Zeit gemessen, die zwischen einem 'DIM f as new Form2' und InitializeComponent auf dem Form2. Dies hat bei meinem Test ca. 15 Sekunden gedauert.

Es scheint also, also ob .NET irgendwas macht was ewig lange braucht.
Tosch 13.01.2014
Kann ich bestätigen @Tosch: frisches Projekt, nur mit dem Unterschied, dass ich das TabControl direkt auf die Mainform geklatscht habe. Und: zieht man um die jeweils 120 Controls ein Panel, nimmt er sich noch einmal 10 Sekunden mehr Zeit... das muss irgendwie mit .Net 4.5.1 zusammen hängen, wie Du schon mal festgestellt hast.
muffi 14.01.2014
Als Bug melden, wenn's so schön nachvollziehbar ist.
cybere 14.01.2014

Stelle deine .net-Frage jetzt!