Jump to content

SUBIECTE NOI
« 1 / 5 »
RSS
Boxa membrana tweeter infundata

ajutor

Whisky for Mac

Xiaomi 14 Gpay
 Izolare zid exterior de scandura

Dezinstalare drivere W11 23H3

Recomandare masina de spalat fiab...

BSOD din cauza Intel Audio DSP dr...
 De ce sunt oamenii nostalgici

Cum vand casa fara factura Hidroe...

Scor FICO minim

Tonometru compensat CAS?
 polita RCA ONLINE

Termostat frigider - verificare

Mai au PC-urile vreun viitor?

Centrala termica immergas
 

utilizarea resurselor: creare si distrugere

- - - - -
  • Please log in to reply
8 replies to this topic

#1
dotniet

dotniet

    Member

  • Grup: Members
  • Posts: 852
  • Înscris: 15.08.2005
Ce poate cauza o eroare de tipul "The block header has been corrupted" in FastMM4?

Edited by ciuly, 18 July 2009 - 10:37.
schimbat titlu, stickyed


#2
ciuly

ciuly

    dus cu pluta pe apa sambetei

  • Grup: Senior Members
  • Posts: 7,848
  • Înscris: 17.03.2004
e posibil sa incerci sa dezaloci o bucata de memorie de mai multe ori. vezi si tu de unde aloci memoria si apoi cauta ce faci cu ea (ai informatiile in raportul generat de fastmm. la nevoie poti da enable la detalii).

si deoarece trebuie, ma repet:

regula de aur:
creare resursa;
try
  utilizare resursa;
finally
  distrugere resursa
end;
indiferent ce anume este resursa aia. ca este un criticalsection.acquire sau deschidere de fisiere sau alocare de memorie, sau creare de obiect, sau alocare un hwnd samd.
iar daca vreti sa prindeti orice exceptie, inclusiv a constructorului, evident, toata povestea de mai sus vine bagat intr-un try/except.
daca, si DOAR DACA, toate clasele voastre sunt scrise corect, abea atunci puteti scrie ceva de genul
creare res1
try
  creare res2
  creare res3 samd
  utilizare resurse
finally
  distrugere res3
  distrugere res2
  distrugere res1
end;
pt ca daca res3 in situatia de mai sus arunca exceptie la distrugere, bye bye distrugere res2 si 1. ce mai puteti face este sa bagati distrugerile in try/finally. pt ca se intampla sa ai nevoie sa creezi vreo 5-7 resurse intr-o metoda si in acest caz identarea codului se va duce foarte la dreapat daca le bagati pe toate in try./finallyuri separate. asa ca puteti folosi doar unul mare, si ca sa fiti chiar siguri, puneti doar distrugerile in finally-uri like so
creare res1
try
  creare res2
  creare res3 samd
  utilizare resurse
finally
  try
	distrugere res3
  finally
	try
	  distrugere res2
	finally
	  distrugere res1
	end;
  end;
end;
la partea de distrugere nu te mai doare asa tare ca se identeaza codul prea la dreapta ca stii ca acolo sunt doar distrugeri.

iar in ceea ce priveste clasele
constructor create
  inherited;  - optional, nu neaparat la inceput (totusi cu grija daca nu e la inceput) depinde de clasa si de constructor. if in doubt, use it
  creare resursa1
  creare resursa2
...
  creare resursan

destructor destroy; override;// obligatoriu override
  distrugere resursa1
  distrugere resursa2
...
  distrugere resursan
  inherited; !!!! - obligatoriu la sfarsit !! (in foarte rare cazuri e nevoide inainte de sfarsit, si doar daca ai ceva experienta vei stii acest lucru)
exact in aceeasi ordine. pt distrugere obiecte sugerez folosirea functiei FreeAndNil
daca a:TObject sau descendent

a:TObject
begin
  a:=nil;
  a.free;// sau freeandnil(a);
end;
NU va genera eroare si nu se va intampla nimic rau. deci sa nu va fie frica ca tot vad o groaza de chestii de genu if assigned(obiect) then
  obiect.free;

este o tampenie. pt ca obiectul ala poate sa nu fie NIL, ci sa aibe o valoare dar obiectul sa fie distrus si atunci se va intampla un AV. si nu vei stii de ce. pe cand daca folosesti freeandnil, daca l-ai distrus odata, a doua oara sigur va fi nil. iar daca primesti un AV cu adresa nil (adica 0 sau un numar mic, care deobicei este adresa metodei in clasa) stii ca il folosesti fie inainte sa il creezi fie dupa ce l-ai distrus (si nu-s multe locuri unde sa cauti chestia asta si macar stii unde sa pui breakpointurile). daca av-u e cu adresa valida atunci mai mult ca sigur obiectul nu e creat sau e distrus dar folosesti o copie a lui aiurea, si iarasi stii unde sa pui breakpointurile. dar altfel, tre sa le pui peste tot.

un alt aspect: metoda destroy a unei clase NU ARE VOIE sa arunce exceptii. aviz amatorilor. doar asa va puteti trezi cu memory leakuri sau chiar cu AV-uri si mai ales cu crash-uri (cel mai adesea).
in aceeasi idee, daca deschideti un fisier in constructor si il inchideti in destructor (intre noi fie vorba e o prostie sa iti gandesti clasa asa), asigurati-va ca faceti inchiderea intr-un try/except.

pt ca daca constructorul esueaza, automat va fi executat destructorul !!! iar daca constructorul nu a apucat sa deschida fisierul, nu aveti ce inchide. la fel faceti la orice dealocare de resurse care poate sa genereze erori. este unul din motivele pt care se prefera utilizarea claselor acolo unde se poate. de ex in loc de File, file of type sau textfile incercati sa folositi TFileStream. samd. ca alternativa frumoasa la try/except este folosirea acelui if assigned(resursa de memorie) sau altor checkuri in functie de resursa in cauza. (dar repet, nu la clase, acolo n-are sens iar pe mine personal ma zgarie pe ochi)

deci nu mai scrieti 
try
  obiect=create
  utilizare obiect
finally
  obiect.free
end;
pt ca destructorul va fi apelat de DOUA ori in cazul in care constructorul esueaza. si n-are sens (mai ales daca nu va asigurati ca destructorul nu arunca exceptii). daca nu ai construit ceva, nu ai ce distruge.

mai departe, daca folositi clase care implementeaza interfete, tineti minte ca ele isi numara instantele automat.
Prin urmare, mare grija daca puneti un astfel de obiect intr-un tag:=integer(obiect). pt ca NU isi va retine instanta si riscati ca refcountu sa ajunga la 0, sa vi se distruga clasa si apoi voi sa folositi TWhatever(o.tag).metoda si boom, AV. si nu stiti de ce. puneti mana pe un tutorial de COM sau lucrul cu interfetele si invatati sa va manageuiti corect interfetele. daca limbajul permite, nu inseamna ca trebuie sa abuzati de tot felul de smecherii, dar daca tot vreti sa o faceti, macar faceti-o cu cap si intelegeti ce se intampla defapt acolo.
si daca tot sunt la interfete, delphi va distruge automat variabilele locale (!) dintr-o metoda/procedura de tip interfete, dynamic arrays si mai stiu eu care. vedeti in help. DAR, asta nu inseamna ca trebuie sa va bazati pe chestia asta. cel mai bine e ca atunci cand faci mizerie sa faci curat dupa tine.

note: AV=Access Violation, totusi daca cititi pe aici ar trebui sa stiti asta (am intalnit programatori care habar n-au de prescurtarile de genu.)

#3
dotniet

dotniet

    Member

  • Grup: Members
  • Posts: 852
  • Înscris: 15.08.2005

View Postciuly, on 18th July 2009, 10:35, said:

a:=nil;
  a.free;// sau freeandnil(a);

Da asta e regula de aur la mine. Probabil ca ar trebui propovaduita ca biblia :)
Nu iti imbunatateste codul cu nimic in sensul functionalitatii insa in caz ca faci prostii ai sanse sa gassti problema mai repede.


Quote

e posibil sa incerci sa dezaloci o bucata de memorie de mai multe ori. vezi si tu de unde aloci memoria si apoi cauta ce faci cu ea
Sunt absolut sigur ca nu e un "dublu free".
Stiu cum suna mesajul de eroare pt asta :) Il mai obtin si pe acela din cand in cand. Insa cu FastMM e usor sa-l "prinzi".

Eroare asta e mult mai serioasa. Ce am gasit azinoapte pe un forum, un tip care a avut aceeasi eroare a zis ca o avea de la o o linie de cod care incerca sa acceseze o bucata de memorie care a fost alocata gresit. Ceva de genul, memoria era alocata, dar nu destula.

var x: TSomething
SetLength(X, PSomething);

Edited by dotniet, 18 July 2009 - 13:44.


#4
ciuly

ciuly

    dus cu pluta pe apa sambetei

  • Grup: Senior Members
  • Posts: 7,848
  • Înscris: 17.03.2004
tu ai un stacktrace pt eroare respectiva generate de fastmm. cu acel stacktrace lucrezi. daca mergi la mecanic si il intrebi: "ce anume poate face motorul sa moara subit" abea se abtine sa nu arunce cu ceva dupa tine. sunt enshpe mii de posibilitati.
intr-adevar, cea mai frecventa posibilitate sa primesti eroarea respectiva este cand suprascrii datele puse de fastmm linga memoria alocata. cum? sunt enshpe mii de posibilitati.
daca nu te descurci tu cu stacktraceu pai posteaza-l, pune si codu relevant si declaratiile variabilelor in cauza sa putem sa ne dam si noi cu parerea pe ceva concret. ca asa, povesti...

#5
dotniet

dotniet

    Member

  • Grup: Members
  • Posts: 852
  • Înscris: 15.08.2005
Treaba cu logul e mai dificila. Nu e mereu la fel.

FastMM has detected an error during a FreeMem operation. The block header has been corrupted.

The current thread ID is 0xB84, and the stack trace (return addresses) leading to this error is:
402E6F [System][@FreeMem]
4068A8 [System][@DynArrayClear]
405DF9 [System][@FinalizeArray]
405CFD [System][@FinalizeRecord]
4042FB [System][TObject.CleanupInstance]
40423E [System][TObject.FreeInstance]
40460D [System][@ClassDestroy]
4D1A0E [SmplCub.pas][SmplCub][TCubObj.Destroy][127]
40428B [System][TObject.Free]
4149B9 [SysUtils][FreeAndNil]
4DAE6E [UnitAsmJob.pas][UnitAsmJob][TAsmJob.Destroy][180]

Current memory dump of 256 bytes starting at pointer address 7FC85780:
00 00 00 00 69 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 54 56 00 00
14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 47 56 00 00 1D 00 00 00...

-------

Oricum, am incercat sa pun un Addreess breakpoint la $7FC85780, si nu merge. Programul nu se opreste.

Breakpoint la adresa $4DAE6, opreste programul aici:

for i:= Count-1 downto 0 DO
  begin
   x:= TCubObj(Self[i]);      
   FreeAndNil(x);
  end;

Edited by dotniet, 19 July 2009 - 15:57.


#6
ciuly

ciuly

    dus cu pluta pe apa sambetei

  • Grup: Senior Members
  • Posts: 7,848
  • Înscris: 17.03.2004

View Postdotniet, on 19th July 2009, 16:54, said:

4DAE6E [UnitAsmJob.pas][UnitAsmJob][TAsmJob.Destroy][180]
acolo e linia cu problema, unitul UnitAsmJob.pas linia 180

View Postdotniet, on 19th July 2009, 16:54, said:

Oricum, am incercat sa pun un Addreess breakpoint la $7FC85780, si nu merge. Programul nu se opreste.
normal. aia e adresa din memorie cand ruleaz aprogramul. ala se modifica la fiecare reincarcare a programului in memorie


View Postdotniet, on 19th July 2009, 16:54, said:

Breakpoint la adresa $4DAE6, opreste programul aici:

for i:= Count-1 downto 0 DO
  begin
   x:= TCubObj(Self[i]);      
   FreeAndNil(x);
  end;
chestia aia e din start gresita.
self[i] e cumva o proprietate
property x[index:integer]:cevaclasa/pointer read write; default;
?
nu e relevant pt problema dar incerc sa inteleg de ce folosesti self[i] cand self se refera la instanta curenta si e indicat sa o folosesti doar cand ai conflicte de scop ale variabilelor/mebrilor/metodelor

in locul tau, din moment ce am o lisat de clase TCubObj as folosi clasa TObjectList din contnrs create cu parametrul freeovjects/ownobjesct sau cum s-o fi numind pe true ceea ce ma asigura ca daca obniectul e distrus sau elementele sunt sterse, vor fi si distruse. deci tot forul tau se oinlocuieste cu un freeandnil(lista:TObjectList) sau lista.clear daca apelul nu e in destructor ci e doar ceva gen clear.

motivele pt care primesti eroare se prea poate ca sunt din cauza de conflict de date/tipuri de date. daca presumtia mea ca self[i] este o proprietate array default, atucni ea trebuie sa intoarca un TObject sau un tip integer pe 32 de biti SAU pe 64 de biti daca platforma pe care rulezi este de 64 de biti iar compilatorul iti face integeru poe atatia biti cat e platforma. aviz amatorilor de casting intre integer si pointer, ca pointeru pe 64 de biti are 64 de biti nu 32. dar ma rog, aici sunt detalii ale compilatorului. un simplu showmessage cu sizeof lamureste problema. oricum, atentie la acest mic amanunta.
revenind, chiar mi se pare o greseala urata faza cu self[i] mutat intr-o variabila ajutatoare CU cast. in momentul in care vrei sa distrugi niste obiecte ale tale, le vei distruge din containerul propriu care este privat (in sugestia mea containerul este lista:TObjectList) dar poate fi orice (un array, un TList, whatever). gandeste-te ca doebicei proprietatile vor expune pe linga datele respective si niste cod. este un overhead facut degeaba, nemaivorbind de problemele care pto aparea dintr-un astfel de model.

sa admitem ca aceasta clasa este threadsafe. din start, accesarea unui element via proprietatea x va avea cel putin un apel la un critical section sau alt mod de sincronizare, pe linga posibilele validari (indexu sa fie in limite, samd)) lucru pe care la o lista de 10000 de elemente, distrugerea iterativa va baga un mare delay degeaba.

-----------
pt a gasi raspunsul la intrebarea ta fara sa bagi rezolvarea sugerata de mine (pe care totusi in final ar trebui sa o bagi) pt inceput, trebuie sa stim:
- platforma pe care rulezi
- platforma pe care compilezi
- daca vreunul e pe 64, daca folosesti ceva librarii sau alte hack-uri pt modificarea/optimizarea codului pt platforma pe 64 de biti (sau eventual daca folosesti dll-uri compilate pt aceasta plaforma si faci schimb de date intre ele prin pointer (inclusiv pchar) si/sau integer)
- cum se creaza self[i] (toate modurile, inclusiv addition daca e cazul)
- cum se distruge self[i] (toate modurile, inclusiv deletion daca e cazul)
- daca TCubObj implementeaza interfete ori ba
- si in final, ce anume e self[i] si daca are ceva cod in spate, mai mult pt curiozitatea mea

foarte util ar fi daca ai putea face un mic demo din aplicatia ta care sa aibe acest behaviour.
daca totul la tine e pe 32 de biti iar self[i] este defapt un TObject sau descendent si nu implementeaza vreo interfata,

SI

valoarea lui self[i] este valida (adica nu te apuci si undeva scrii self[i]:=whatever (fie direct prin self[i] fie prin intermediul containerului)

pune un breakpoint in destructorul lui TCubObj (il creezi daca nu exista ) si vezi exact de unde se distruge. daca aplicatia e complicata, atunci optim ar fi sa poti loga stacktraceul (exista mai mutle posibilitati, madexcept, jedi, eureka, samd)

o alta modalitate de a verifica validitatea pointerilor este sa pui breakpoint cand adaugi in lista, cand modifici din lista cand stergi din lista si in foru ala al tau. la primu element adaugat, notezi adresa si apoi modifici proprietatile breakpointurilor sa opreasca cand se opereaza cu prima valoare (adica indexu 0, nu valoarea notata). cand intra breakpointu, verifici valoarea din pointer cu ce ai notat inainte si dupa operatie. e probabil ca daca faci ceva gresti pe acolo sa iti dai seama unde si care e probelama.

#7
dotniet

dotniet

    Member

  • Grup: Members
  • Posts: 852
  • Înscris: 15.08.2005
Bucata de cod e dintr-un obiect derivat din TObjectList.
De aici vine self. :)

Folosesc Delphi 7. Abia astept sa apara Delphi pe 64 bit (imi trebuie support pt mai mult de 4GB RAM).

Quote

foarte util ar fi daca ai putea face un mic demo din aplicatia ta care sa aibe acest behaviour.
Yep. asta e problema mea! Bug-ul nu apare decat cand folosesc tot codul impreuna, cred ca peste 20 unit-uri, si nici atunci mereu.
Primul lucru  pe care l-as fi acut si eu ar fi fost sa sparg aplicatia in bucati mici ca sa izolez problema. Insa daca modific putin codul sursa problema dispare. La fel se intampla si daca incarc de pe disk alt set de date.

Mersi pt ajutor. O sa gasesc eu cumva problema pana la urma. Am inceput sa inspectez toate unit-urile, linie cu linie, sa caut posibile erori si sa aduc imbunatatiri sau sa curat codul.

Edited by dotniet, 19 July 2009 - 18:47.


#8
ciuly

ciuly

    dus cu pluta pe apa sambetei

  • Grup: Senior Members
  • Posts: 7,848
  • Înscris: 17.03.2004

View Postdotniet, on 19th July 2009, 19:41, said:

Bucata de cod e dintr-un obiect derivat din TObjectList.
De aici vine self. :)
pai si atunci de ce nu folosesti clear? :huh:

#9
dotniet

dotniet

    Member

  • Grup: Members
  • Posts: 852
  • Înscris: 15.08.2005

View Postciuly, on 19th July 2009, 21:11, said:

pai si atunci de ce nu folosesti clear? :huh:

Bucata aia de cod era doar pt debugging. Vroiam sa vad unde apare eroarea.
Oricum s-a rezolvat. Azi am revizuit cea mai mare parte din cod, am facut chiar o mutime de schimbari si am scapat de eroare. Nu sunt sigur de unde a fost. Nu am stat sa recompilez dupa fiecare eroare.

Multumesc mult pt ajutor!

Anunturi

Chirurgia endoscopică a hipofizei Chirurgia endoscopică a hipofizei

"Standardul de aur" în chirurgia hipofizară îl reprezintă endoscopia transnazală transsfenoidală.

Echipa NeuroHope este antrenată în unul din cele mai mari centre de chirurgie a hipofizei din Europa, Spitalul Foch din Paris, centrul în care a fost introdus pentru prima dată endoscopul în chirurgia transnazală a hipofizei, de către neurochirurgul francez Guiot. Pe lângă tumorile cu origine hipofizară, prin tehnicile endoscopice transnazale pot fi abordate numeroase alte patologii neurochirurgicale.

www.neurohope.ro

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

Forumul Softpedia foloseste "cookies" pentru a imbunatati experienta utilizatorilor Accept
Pentru detalii si optiuni legate de cookies si datele personale, consultati Politica de utilizare cookies si Politica de confidentialitate