Răspunsul la întrebarea nr. 67208

Problema alocării memoriei pentru rețelele dinamice.

La alocarea următoare a memoriei sub o matrice dinamică:

tip TArrayOfDouble = matrice de duble;
Var ArrayRunEvolutionFits: matrice de TArrayOfDouble;






...
SetLength (ArrayRunEvolutionFits, NRun);

Deblocare notificare de primire
Proiectul ProjectPDB.exe a ridicat clasa excepțională EAccessViolation cu mesajul "Încălcarea accesului la adresa 00405F13 în modulul" Project.exe ". Citiți adresa 00000003 ". Procesul sa oprit. Utilizați pasul sau executați pentru a continua.

Proiectul este compilat și programul funcționează până când acesta se produce în timp ce executați linia de mai sus. Procedurile care nu sunt legate de această matrice funcționează de asemenea.

Eroarea a început să apară după adăugarea ulterioară a unei noi matrice dinamice (altele), care lucrează singure. Dacă le ștergeți, eroarea nu mai apare.

Programul este scris în mediul Delphi 7 și este destinat sarcinilor de cercetare în domeniul studierii structurii moleculelor de proteine. În ordinea de proiect de 20 de unități, numai componente standard și OpenGL sunt utilizate pentru vizualizarea molukulului. Deoarece dimensiunea seturilor de date nu este cunoscută în prealabil, folosim matrice dinamice. Rețelele în sine nu depășesc 50 000 dubluri.

La un moment dat, o eroare similară a apărut deja, apoi în Project Options \ Linker creșterea maximă a stackzize la $ 01000000 a permis rezolvarea problemei.

Există o oportunitate de a rezolva această problemă acum? Poate că a existat o eroare de alocare a memoriei; poate că există utilități care ajută la urmărirea alocării memoriei?

O altă posibilitate, cred, este înlocuirea unor rețele cu structuri de tip TList. pentru a descărca stivă. Dar va fi o soluție?

Urmăriți răspunsurile la această întrebare prin RSS

la Dmitri Shatalov
Motivul erorii este o depășire trivială a matricei care apare
din cauza unei comparații incorecte a numerelor reale.

Dacă puneți contoarele în fiecare ciclu, veți vedea asta
- în primul ciclu, pur și simplu "norocos" - există 4000 de apeluri el-tov și 4000 de apeluri către matrice.
Acest lucru se datorează faptului că în condiția timpului<=40 do begin равенство zd=40 не отрабатывается.
- în al doilea ciclu nu sunteți "norocoși" - se adaugă încă 1000 de el-tov și
atunci 1001 accesează matricea. Acest lucru se datorează faptului că în condiția timpului<=50 do begin
Egalitatea zd = 50 este elaborată și, ca o consecință, este obținută de una
mai mult => în afara domeniului.

De asemenea, dacă există posibilitatea de a seta numărul de el-tov al matricei, este mai bine
face-o imediat.

Bună ziua. Întrebarea, desigur, este veche, dar greșeala mea a fost aceeași. În cazul în care articulația nu este clară. Programul utilizează o matrice dinamică:

procedura createpart;
const da_len = 12;
var
profZall: matrice de matrice de duble;
h: dublu; // incrementarea coordonatei longitudinale
Vr, Vrmin: dublu; // Contur și viteze reduse de tăiere a conturului
j_int: Cuvant lung; // increment pentru a umple matricea
zd, xd: dublu; // coordonatele curente ale părții

procedură addpoint (z, x, v: dublă); // umplerea ultimului element al matricei
var i: cuvânt lung;
începe
profZall [0, j_int]: = 0; // în timp ce umpleți ora cu valori zero
profZall [1, j_int]: = Z;
profZall [2, j_int]: = X;
profZall [3, j_int]: = V;
pentru i: = 4 la (da_len-1) face profZall [i, j_int]: = 0; // umple restul cu valori zero
inc (j_int);
se încheie;

j_int: = 0;
zd: = 0;
// setlength (profZall, da_len, 500000);

// graficul liniei drepte orizontale 40 mm






setlength (profZall, da_len, rotund (40 / h)); // numărul de e-in este de 4000
în timp ce zd<= 40 do begin
xd: = 50;
punct de adăugare (zd, xd, vr);
zd: = zd + h;
se încheie;

// un sfert dintr-un cerc - o tranziție de-a lungul razei
setlength (profZall, da_len, j_int + rotund (50 / h-40 / h)); // numărul de el-in este de 5000
în timp ce zd<= 50 do begin
xd: = 60-în jurul (sqrt (sqr (10) -sqr (zd-40)), - 6);
punct de adăugare (zd, xd, Vrmin);
zd: = zd + h;
se încheie;

// secțiunea opt cercuri - tranziția de-a lungul razei
setlength (profZall, da_len, j_int-1 + rundă (130 / h-50 / h)); // ar trebui să fie egal cu 13000, dar există o excepție

j_int: = j_int; // debug
se încheie;

Ceea ce este interesant, dacă vă pokoldovat și adăugați alte resturi de calcul, totul poate funcționa și normal. Totuși, sarcina unui număr foarte mare de elemente (50.000) este înghițită, dar răspunsul apare încă în același loc.
Un alt cod foarte interesant se comportă dacă procedura este împinsă în aplicația consolei. Se pare că cilindrii de atribuire, dar linia j_int salturi: = j_int; și blochează operația InvalidFloatingPointer. Atribuirea unui matrice la zero nu ajută. În general, unele glitches.
Da, mediul de dezvoltare D7

Rezultatul rezolvării problemei. în mod neașteptat, problema a fost rezolvată (pentru totdeauna sau doar pentru moment) prin permutarea apelurilor funcțiilor SetLength:

codul sursă alocă memoria pentru 3 rețele dinamice:
.
SetLength (ArrayRunEvolution, NRun);
SetLength (ArrayRunEvolutionFits, NRun);
SetLength (ArrayRunEvolutionBestFits, NRun);
.
A apărut o eroare EAccessViolation în al doilea rând pentru ArrayRunEvolutionFits. În timpul rezolvării problemei, codul a fost modificat în mai multe locuri, având în vedere sfatul 777 referitor la utilizarea lui Low (), High (). Dar, în timpul executării programului, eroarea a avut loc încă în același loc.

De altfel, a apărut ideea de a schimba ordinea de alocare a memoriei. Eroarea a dispărut când primele două linii au fost mutate.

Repoziționarea rândurilor în poziția lor inițială la EAccessViolation nu este rezultatul!

Din păcate, acum nu există o versiune a proiectului cu o eroare. Nu puteți să returnați înapoi EAccessViolation. Rămâne să sperăm că eroarea a fost o vină a compilatorului Delphi și nu folosirea incorectă a datelor dinamice.

MBO. acordați atenție codului:

pentru iRun: = 1 la nRun nu începe
...
ReadRunEvolution (ArrayRunEvolution [iRun-1]);
...
se încheie;

1. Totul este corect aici.
2. Programul nu ajunge la completarea acestei linii, la afișarea unei erori
3. Opțiunea "Verificarea intervalului" este activată, iar în cazul unei astfel de supravegheri, eroarea ar fi în timpul compilării
4. Anterior, acest loc a funcționat (eroarea a început să apară după adăugarea următoarelor agende dinamice noi. După eliminare, eroarea nu mai apare).
5. Este foarte asemănător memoriei de memorie menționată de Anton. Dar cum o să prinde? Încerc să folosesc Debug pentru a identifica sursa erorii

> pentru iRun: = 1 la nRun
Aici, câinele a răsunat.
seturile dinamice sunt numerotate de la zero.

Cred că există mai multe locuri în program.
Deci, sfatul despre Low-High este foarte aproape de subiect.

Vă mulțumesc tuturor pentru răspunsurile dvs.

Anton. Vă mulțumim pentru clarificări cu privire la pâlpâirea memoriei. Este foarte asemănător cu această eroare și, cel mai probabil, furtul nu este conectat la matricea pe care apare încălcarea Access. Repet, o situație similară a fost deja întâlnită, dar, din păcate, sursa erorii nu a fost stabilită. În primul caz, stiva a fost extinsă și acest lucru a ajutat, iar în al doilea, codul a fost optimizat, eliminând structurile dinamice deja inutile și programul a funcționat pe deplin. Apoi a existat o impresie că nu era suficient stivă.

Matvey. multumesc pentru link-ul catre acedutils si un memento despre Knuth.

MBO. Iată codul:

tip TArrayOfDouble = matrice de duble;
Var ArrayRunEvolutionFits: matrice de TArrayOfDouble;
...
SetLength (ArrayRunEvolutionFits, NRun);
...
pentru iRun: = 1 la nRun nu începe
...
ReadRunEvolution (ArrayRunEvolution [iRun-1]);
...
se încheie;

// unde funcția ReadRunEvolution este un difiniran, cum ar fi

funcția ReadRunEvolution (var se potrivește: TArrayOfDouble);

// și în ea memoria este alocată pentru al doilea nivel.

Cel mai probabil, eroarea apare mai devreme, dar apare numai în această linie. Rețin încă o dată că dacă programul nu utilizează această funcție, efectuează alte operații, atunci totul funcționează, nu există erori.

Stingerea memoriei este atunci când ceva este scris într-o zonă de memorie, ocolind acele proceduri care l-au evidențiat și sunt responsabile de ea. Ca urmare, este încălcată coerența datelor stocate acolo, ceea ce poate duce la erori foarte diferite în operațiile ulterioare care afectează această memorie.

O altă posibilitate, cred eu, este înlocuirea unor rețele cu structuri de tipul TList, pentru a descărca stivă. Dar va fi o soluție?
Cu o dimensiune de 50.000 de elemente, structurile copacilor devin foarte eficiente. Algoritmii, motivele și calculele matematice despre viteza teoretică sunt prezentate în Knut în capitolul 6 al celui de-al treilea volum. Deci, mai întâi poți să te uiți la acedutils.

ype TArrayOfDouble = matrice de duble;
Var ArrayRunEvolutionFits: matrice de TArrayOfDouble;
...
SetLength (ArrayRunEvolutionFits, NRun);

Aici vedem că variabila este o matrice bidimensională, iar SetLength se face numai pentru prima dimensiune.
Alocarea memoriei pentru matricele de nivelul al doilea este uitată?







Articole similare

Trimiteți-le prietenilor: