Laden...

OLEdBDataReader bringt den Speicher an seine Grenzen

Erstellt von Soier vor 5 Jahren Letzter Beitrag vor 5 Jahren 3.586 Views
S
Soier Themenstarter:in
25 Beiträge seit 2014
vor 5 Jahren
OLEdBDataReader bringt den Speicher an seine Grenzen

verwendetes Datenbanksystem: diverse

Hi, ich schreibe momentan eine Anwendung die diverese Datenbanksysteme unterstützen soll. Als Schnittstelle nutze ich deshalb OLEDB.

In der Anwendung mache ich vorher ein SELECT COUNT (*) from Table um die Anzahl der Datensätze der zu bearbeiteten Tabelle zu ermitteln, den bei zu grossen Tabellen(Habe mich für 10.000 Datensätze entschieden) sollen die Daten einzeln bearbeitet werden. Dies hat den Grund ich möchte eine OutOfMemory-Exception vermeiden. Jedoch fand ich Raus das in der Schleife in der ich den Reader abarbeite der speicher mit jeder Iteration wächst. Gibt es eine Möglichkeit die Daten vom Reader nach jeder Iteration vom Speicher zu löschen?

16.806 Beiträge seit 2008
vor 5 Jahren

Es macht keinen Sinn, dass 10000 Einträge in einer Tabelle stecken. Wer soll denn das lesen, geschweige denn bearbeiten können?
Deswegen gibt es Paging.

Und zum Problem: zeig mal bisschen Code.

PS: der Arbeitsspeicher im Taskmanager ist keine genaue Angabe.
Es spricht aber dafür, dass Du einen Konzeptfehler hast.

die diverese Datenbanksysteme unterstützen soll. Als Schnittstelle nutze ich deshalb OLEDB.

Das alleine ist kein Grund für direktes OleDB.
Dazu gibt es seit Jahren ADO.NET, sodass man sich mit dem OleDB Zeug nicht rumschlagen muss.
Mich würde es jetzt wundern, wenn Du ein Szenario hast, das OleDB zulässt aber kein ADO.NET.

T
461 Beiträge seit 2013
vor 5 Jahren

Es macht keinen Sinn, dass 10000 Einträge in einer Tabelle stecken. Wer soll denn das lesen, geschweige denn bearbeiten können?
Deswegen gibt es Paging.

Ich denke das mit den 10000 war auch das Paging selbst gemeint. Also immer 10000 Einträge lesen und verarbeiten.

Bei Daten-schaufeln (Stammdatenimporte) kann das schon ein Thema sein...

Rest wurde ja schon genannt.

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

S
Soier Themenstarter:in
25 Beiträge seit 2014
vor 5 Jahren

Ich denke das mit den 10000 war auch das Paging selbst gemeint. Also immer 10000 Einträge lesen und verarbeiten.

Bei Daten-schaufeln (Stammdatenimporte) kann das schon ein Thema sein...

Rest wurde ja schon genannt.

Ja Genau um das Handelt es sich. Wegen OLEDB das problem ist ein Datenbanksystem benötigt .dlls für eine verbindung und mir steht nur die OLEDB dll zur Verfügung welche auch noch nur als 32 bit Variante da ist. Deshalb muss die Anwendung 32 bit compiliert werden.

Hab mal um den Fehler besser zu lokalisieren eine Kleine Testanwendung geschrieben und eine Oracle datenbank genommen bei 32 bit tritt der Fehler auf bei 64 bit nicht. Der Fehler tritt genau beim Schleifen kopf auf und auch erst nach einer gewissen Zeit wenn laut Dignostic Tool die Anwendung über 3,8 GB Ram verwendet. der Fehler lautet > Fehlermeldung:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt Bin am überlegen für die Anwendung zwei binary anzulegen eine 32-bit wenn umbedingt benötigt und eine 64 bit variante oder gibt es Programmiertechnisch noch ne möglichkeit

T
461 Beiträge seit 2013
vor 5 Jahren

Hallo,

es wäre mal ein wenig Code nicht schlecht zu sehen und die ganze Fehlermeldung.

Zudem bitte das von Abt beherzigen: ADO.NET, gibt es natürlich auch für OLEDB...

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

S
Soier Themenstarter:in
25 Beiträge seit 2014
vor 5 Jahren

Also nutze nun ADO.Net mit Oledb.

                using (OleDbDataReader myreader = selectcommand.ExecuteReader())
                {

                    for(int i = 0; i < myreader.FieldCount; i++)
                    {
                        myTable.Columns.Add(myreader.GetName(i), myreader.GetFieldType(i));
                    }

                    while (myreader.Read())
                    {
                        
                        myDatarow = myTable.NewRow();

                        for(int i = 0; i < myreader.FieldCount; i++)
                        {
                            myDatarow[i] = myreader[i];

                        }

                        myTable.Rows.Add(myDatarow);
                        count++;

                        if(count == 10000)
                        {
                            myTable.Rows.Clear();
                            count = 0;
                        }
}

also er durchläuft die Schleife einige male und nach einiger Zeit bringt er die besagte Meldunng: > Fehlermeldung:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt . Hab auch Spaßes halber mal die schleife leer gelasen da läuft der reader die schleife komplett durch

T
461 Beiträge seit 2013
vor 5 Jahren

Hallo,

das was ich hier weiß ist das, daß dieser Code sicher nicht ganz richtig ist.

Für SQL gäbe es folgende Lösungen für das Paging:


CREATE PROCEDURE [dbo].[StoredProcName] 
    @page_size INT
    , @page_num INT
AS
BEGIN

    SET NOCOUNT ON;

    ; WITH RESULTS AS
    (
        SELECT *
            , ROW_NUMBER() OVER (ORDER BY <order_col> DESC) AS rn
            , ROW_NUMBER() OVER (ORDER BY <order_col> ASC) AS rn_reversed
        FROM <table>
    )
    SELECT *
        , CAST(rn + rn_reversed - 1 AS INT) AS total_rows
        , CAST(CASE (rn + rn_reversed - 1) % @page_size
            WHEN 0 THEN (rn + rn_reversed - 1) / @page_size
            ELSE ((rn + rn_reversed - 1) / @page_size) + 1 
            END AS INT) AS total_pages
    FROM RESULTS a
    WHERE a.rn BETWEEN 1 + ((@page_num - 1) * @page_size) AND @page_num * @page_size
    ORDER BY rn ASC 

END

Quelle dazu

Alternativ mit SELECT TOP und einer Nummern-Schlüsselspalte...

Hi, ich schreibe momentan eine Anwendung die diverese Datenbanksysteme unterstützen soll.

Mit ADO.NET kannst du das ganze so abstrahieren, daß du tatsächlich mehrere Datenbanktypen abdecken kannst, hier ein Beispiel dazu.

Für das Paging anderer Datenbanktypen kann ich leider noch nichts dazu sagen.

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

S
Soier Themenstarter:in
25 Beiträge seit 2014
vor 5 Jahren

Hi,

ich hab jetzt das mit dem pageing implementiert allerdings ohne erfolg nach ner zeit bringt er bei adapter.fill() den fehler (sogar wenn ich diesen part in einen try-catch block ausführe). Der Fehler tritt auch wieder nur bei 32 bit auf wenn ich die funktion testhalber in 64 bit ausführe dann geht das ohne probleme

16.806 Beiträge seit 2008
vor 5 Jahren

Dann zeige bitte den vollständigen Code.
Wir können leider noch nicht hellsehen 😃

F
10.010 Beiträge seit 2004
vor 5 Jahren

Naja, Adapter.Fill bedeutet das du mit diesen unsäglichen DataTables arbeitest die Speichermonster sind.

Was machst du also wirklich?
Adapter.Fill oder mit einem DataReader arbeiten?

Und der Code da unten ist nicht dein ernst, oder?
Du baust den DataAdapter halb nach, schmeißt aber nach 10.000 eingelesenen Datensätzen diese einfach weg?

S
Soier Themenstarter:in
25 Beiträge seit 2014
vor 5 Jahren

@FZelle Der Code war nur ein Testcode um zuschauen, ob der Fehler wirklich beim Lesen der Daten auftritt, was er tut. Ich hab jetzt beides probiert Adapter.fill mit nem Datareader nach zu bauen und via Paging die Daten batchweise einzulesen jedes mal tritt der Fehler auf.

	OleDbDataAdapter myAdapter = new OleDbDataAdapter(selectstring, myConnection);
	int pagesize = 10000;
	
	for(int i = 0; i <= zeilenanzahl/pagesize; i ++)
	{
		Dataset myData = new Dataset();
		
		myAdapter.fill(myData, i * pagesize, pagesize, "myTable");
		
		myData = null;
	
	}

wie gesagt hier geht grad nur darum die Daten auszulesen, da dabei schon der Fehler auftritt und auch nur wenn ich das ganze 32-Bit laufen lasse, in 64 bit geht das problemlos. Allerdings soll die Anwendung später unter 32 -Bit laufen, da die Anwendung auf .dll zugreift die nur 32-Bit verfügbar sind.

S
248 Beiträge seit 2008
vor 5 Jahren

Hallo Soier,

hast du es mal mit einer kleineren Pagesize versucht und geschaut ob der RAM immernoch voll läuft?
Mir fällt noch auf, dass du bei dem Aufruf von fill(..) immer 'pagesize' viele Zeilen liest? Funktioniert das wirklich - auch wenn 'zeilenanzahl' kein Vielfaches von 'pagesize' ist?

Grüße
spooky

T
461 Beiträge seit 2013
vor 5 Jahren

hast du es mal mit einer kleineren Pagesize versucht und geschaut ob der RAM immernoch voll läuft?

Der RAM läuft nicht voll die Fehlermeldung sagt folgendes aus:> Fehlermeldung:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt

Funktioniert das wirklich - auch wenn 'zeilenanzahl' kein Vielfaches von 'pagesize' ist?

Soweit ich es **nachgelesen **hatte, sollte es egal sein.

Ich verstehe nicht, warum er das unbedingt mit Oledb machen möchte, denn den derzeitigen Datenbanktyp hat er ja nicht genannt, oder?

Warum nutzt du nicht die Lösung der Prozedur, diese kümmert sich um das Paging, man muß halt nur die Prozedur aufrufen mit den notwendigen Parametern.
Dann kannst auch mit dem DataReader arbeiten und nicht mit DataTables...

Wenn es möglich ist, würde ich mal mit Sql Arbeiten und nicht mit Oledb und dann eruieren ob der Fehler noch immer auftritt.

Was ich so ein wenig gelesen hatte, hat es unter Umständen was mit dem .NET Framework zu tun unter dem man arbeitet und auch die Version vom VisualStudio, sind aber nur gelesene Vermutungen.

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

S
248 Beiträge seit 2008
vor 5 Jahren

Der RAM läuft nicht voll

Hmm, mag sein. Trotzden klingt 3,8GB bei einem 32bit Prozess erstmal nicht so gut. Vielleicht ist die Fehlermeldung nicht korrekt ... wäre nicht das erste Mal.
Dies würde zumindest erklären warum es mit 64bit funktioniert ... natürlich kann dies auch andere Gründe haben. Trotzdem könnte man es prüfen.

Grüße

T
461 Beiträge seit 2013
vor 5 Jahren

Der RAM läuft nicht voll
Hmm, mag sein. Trotzden klingt 3,8GB bei einem 32bit Prozess erstmal nicht so gut.

Diese hohe Auslastung hat mit dem ersteren Code von ihm zu tun, was mich auch nicht wundert. Für letzteres gibt es noch keine genaueren Informationen, da der Threadhersteller immer sehr knapp mit seinen Infos ist...

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

L
136 Beiträge seit 2015
vor 5 Jahren

Hallo zusammen,

Mit einem 32 bit System lassen sich 2^32, also ungefähr 4GB Arbeitsspeicher adressieren.
Verwundert also nur wenig, wird der Prozess abgewürgt... 😁

Gruss Lhyn

S
Soier Themenstarter:in
25 Beiträge seit 2014
vor 5 Jahren

also das der Speicher knapp wird schliesse ich mal aus. Beim Paging wird die Exception geschmissen bei ca. 1,6GB Speicherverbrauch(laut Diagnostic tool). Wie auch von Thomas bereits erwähnt, hab ich auch gelesen das es am Framework liegt. Hab zwischen 4.0 und 4.6.1 ma getestet ohne jeglich Änderung

16.806 Beiträge seit 2008
vor 5 Jahren

Bitte zeig wo Du gelesen hast, dass am Framework liegt.
Das ist nämlich totaler Quatsch.

Es liegt an der Art und Weise wie Du arbeitest: mit speicherfressenden DataTables.

Die maximale Größe eines CLR Objekts kann 2GB sein. Das Large Object Limit gibt es erst seit .NET 4.5 und muss aktiviert werden.
Die Adressierbarkeit des Betriebssystems spielt dabei keine Rolle. Daher bringen die Hinweise auch nichts.

S
Soier Themenstarter:in
25 Beiträge seit 2014
vor 5 Jahren

Ich komme ja noch nichtmal an die 2GB, außerdem handelt es sich ja nicht um eine OutOfMemory exception. So wie ich das verstehe Versucht er auf eine Stelle im Speicher zu zugreifen wo er nicht kann.

T
2.219 Beiträge seit 2008
vor 5 Jahren

@Soier
Das du an das Limit kommst, ist ja auch nicht das Problem.
Ein ähnliches Problem hatte ich früher auch mit .NET 2.0 und den DataTables.
Dort wurde bei korrektem Code auch immer wieder diese Meldung geworfen.
Erst die Umstellung von DataTable auf eine einfache List<T> mit einem entsprechenden Datentypen hat das Problem gelöst.
Der Fehler lies sich auch nicht immer auslösen, trat also auch immer zufällig auf.
Ich verwende das DataTable auch nur noch wenn es sein muss.

Gerade bei deiner Einschänkung bei einem 32 Bit System würde ich ein Custom Paging nicht mit hilfe des DataTable umsetzen.
Meine Empfehlung wäre es über den DataReader ein einfaches Objekt zu befüllen, was alle Daten aus deinem DataTable repräsentiert.
Also pro Spalte eine entsprechende Property mit passendem Datentypen.
Ist anfangs erst einmal aufwändiger aber schon die einfachere handhabung sowie der sinkende Speicherverbrauch werden es dir danken.

Also tue dir selbst einen gefallen und verwirf das DataTable und mach es selbst über den DataReader!

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.806 Beiträge seit 2008
vor 5 Jahren

Ich komme ja noch nichtmal an die 2GB, außerdem handelt es sich ja nicht um eine OutOfMemory exception.

Und wenn Du mal anschaust, wie .NET funktioniert, dann wirst Du entdecken, dass (Speicher)limits nicht zwangsläufig in einer OutOfMemoryException enden und selbst OutOfMemoryExceptions nicht nur Speicherlimits repräsentieren...

Aber Du bist Dein eigenes Glückes Schmied.
Du kannst jetzt so weiter machen und die veralteten DataTables mit ihren Vor- und Nachteilen verwenden; oder Du machst es eben modern.
Liegt jetzt an Dir.

T
2.219 Beiträge seit 2008
vor 5 Jahren

@Abt
Ich würde weniger modern sagen als mehr effizient in hinsicht auf Speicherverbrauch und Handling der Daten.
Ich denke mal alleine die Umstellung von DataTable zu einem eingenen Objekt könnte den auch schon den RAM Verbrach locker bis zum Faktor 10 verkleinern.
Hängt aber von der Anzahl an Spalten und deren Datentypen im aktuellen DataTable ab.

@Soier
Worauf Abt mit OutOfMemory anspielt ist in der Doku auch noch nachzulesen.
Hier bezieht er sich auf Leaking von Unmanged Resourcen, die noch per Dispose freigegeben werden müssten.
Vermutlich könnte dies auch eine Fehlerquelle in deinem Code sein, wenn du z.B. die Verbindung o.ä. Objekte deren Klassen von IDisposable abgeleitet sind, nicht selbst oder per using disposed.

Links:
https://docs.microsoft.com/en-US/dotnet/api/system.outofmemoryexception?view=netframework-4.7.2
https://docs.microsoft.com/en-us/dotnet/api/system.idisposable?view=netframework-4.7.2

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.806 Beiträge seit 2008
vor 5 Jahren

Ich würde weniger modern sagen als mehr effizient in hinsicht auf Speicherverbrauch und Handling der Daten.

Ich bleibe bei meiner Formulierung 😃

Worauf Abt mit OutOfMemory anspielt ist in der Doku auch noch nachzulesen.
Hier bezieht er sich auf Leaking von Unmanged Resourcen, die noch per Dispose freigegeben werden müssten.

Nein.

Im Prinzip beziehe ich mich allgemein darauf, dass einem Betriebssystem die verfügbaren Handles ausgehen können, das dann mit einer OutOfMemoryException quittiert wird.
Dieses Limit ist nicht fix, aber hat Limits bzgl. Thread, Prozess und Co.

Dazu gehören auch Unmanaged Ressources - aber nicht nur.

S
Soier Themenstarter:in
25 Beiträge seit 2014
vor 5 Jahren

Alles Klar werde es mit der List<T> probieren. Allerdings ein problem hab festgestellt das der DataReader bei den Problem Tabellen nicht komplett durch die Tabelle durch iteriert, sprich er geht aus der Schleife ohne jede Datensatz gelesen zu haben

2.298 Beiträge seit 2010
vor 5 Jahren

Dann solltest du mit dem Debugger prüfen, warum er aus der Schleife aussteigt obwohl noch zu lesende Daten vorhanden sind.

Entweder es sind alle Tabellen gelesen und somit keine Daten mehr zum Lesen vorhanden oder aber du schluckst irgendwo eine Exception.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

T
461 Beiträge seit 2013
vor 5 Jahren

Allerdings ein problem hab festgestellt das der DataReader bei den Problem Tabellen nicht komplett durch die Tabelle durch iteriert

Entweder wie von @inflames2k gesagt oder es fehlt dir einfach die Grundlage: OleDbDataReader

Um an diese Info zu kommen, kann man (in meinem Fall 😁 ) Bingen: https://www.bing.com/search?q=Oledbdatareader&pc=MOZI&form=MOZTSB

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

S
Soier Themenstarter:in
25 Beiträge seit 2014
vor 5 Jahren

Jo es wird die Exception verschluckt wenn ich in der Schleife die erste Spalte ausgebe tritt der Attempted to read or write protected memory Fehler wieder auf. Ich hab mir jetz überlegt das ich das ich die Grossen Tabellen nicht mehr mit einem einfachen SELECT * selektiere sondern via Pagining selektiere in meiner Versuchsapplikation scheint das zu funktionieren