Delphi7 stack overflow probléma

Delphi7 stack overflow probléma
2016-11-23T15:59:44+01:00
2016-11-23T21:26:08+01:00
2022-10-15T22:15:50+02:00
vandammee
Sziasztok!

Delphi7-ben (32bites Win7 alatt) írok egy programot, amiben egy adatfile-ból nagy mennyiségű adatot szeretnék egy tomb-be tölteni, hogy aztán kiértékeljem.

A tomb deklarációja:
pont:array[1..30000] of Tadat; A Tadat deklarációja: Tadat=record X,Y:integer; A,B,C:real;
Namost amikor futtatom a programot, akkor 'Stack overflow' hibaüzenetet kapok.
Ha a pont tömb méretét elkezdem csökkenteni 1000-sével, akkor mikor elérem a 25000-ret, akkor az 'access violation at 0x77b9f94c: write of address 0x00030fb0' hibaüzenetet kapom. Ha lemegyek 24000-re vagy alá, a programom fut rendesen.

Namost a Delphi7 helpje szerint az integer 4 byte, a real 8 byte, azaz 1 Tadat rekord összesen 32 byte,
26000 db Tadat rekord 832000 byte, azaz nincs 1 MB.

Szeretném jobban megérteni, mi történik. Valami olyan rémlik, hogy a számítógép memóriája két fő részre tagolódik, a veremre (stack), meg a halomra (ennek nem emlékszem az angol megfelelőjére).

Gondolom azért kapom a stack overflow hibát, mert ennek mérete kisebb, mint 832000 byte az esetemben. Honnan tudom, hogy az adott számítógépen ez mekkora? Hogy lehet ezt megtudni?
Mutasd a teljes hozzászólást!
Szia!
A memóriában sokkal több minden van, mint verem és halom. Például ott van még a programod is És a globális változók értékei stb. Amúgy a halom egy olyan memóriaterület, amiből programfutás közben lehet plusz memóriát nyerni tárterületnek. Például a nagy tömbödnek.

A lényeg, hogy nem okvetlen használhatod ki az 1MB veremméretet és nem is bízhatsz benne, hogy biztosan ilyen nagy. A kódban 30000 elemű a tömböd, x 32 bájt az már 960000 majdnem eléri az 1MB-ot!!!

Először is kapcsold be a stack overflow vizsgálatot, rögtön meg fog állni a megfelelő hibával.

Másodszor pedig használj abból a bizonyos halomból kért tárterületet, pl:

type pPontArray = ^tPontArray; tPontArray = array[1..30000] of Tadat; : : : procedure IttKellNagyTomb(); var T : pPontArray; begin New(P); try T^[16].X:=5; // kell az a kis kalap! finally Dispose(P); end; end;
Vagy még egyszerűbb a dinamikus tömb, az ugyanezt automatikusan csinálja:

procedure IttKellNagyTomb(); var T : array of Tadat; begin SetLength(T,30000); T[16].X:=5; //mint minden más tömb, úgy használható end;
szerk. úgy látom, kicsit lemaradtam, de hátha hasznos
Mutasd a teljes hozzászólást!

  • Helló

    Nagyobb struktúrákat nem szoktunk a stack-ben átadogatni, az nem arra való, viszont pl. a címét már átadhatod. Valószínűleg valami eljárásba adod át ezt a struktúrát, ott próbáld referencia szertint átadni a paramétert, pl:
    valamieljaras(atomb: tomb) helyett valamieljaras(var atomb: tomb)

    Üdv

    GyK
    Mutasd a teljes hozzászólást!
  • Szia!

    Hát egyszer Menu: Project\Options\Linker\Memory size\Max stack size

    Ezt próbál feljebb venni, ha ekkor is jelentkezik a probléma nem (csak) ezzel van a probléma... mert azt se felejtsd el hogy maga a program is használ memóriát!

    Ha nem segít, akkor jó lenne kódot látni! 

    BySzi
    Mutasd a teljes hozzászólást!
  • Szia!
    A memóriában sokkal több minden van, mint verem és halom. Például ott van még a programod is És a globális változók értékei stb. Amúgy a halom egy olyan memóriaterület, amiből programfutás közben lehet plusz memóriát nyerni tárterületnek. Például a nagy tömbödnek.

    A lényeg, hogy nem okvetlen használhatod ki az 1MB veremméretet és nem is bízhatsz benne, hogy biztosan ilyen nagy. A kódban 30000 elemű a tömböd, x 32 bájt az már 960000 majdnem eléri az 1MB-ot!!!

    Először is kapcsold be a stack overflow vizsgálatot, rögtön meg fog állni a megfelelő hibával.

    Másodszor pedig használj abból a bizonyos halomból kért tárterületet, pl:

    type pPontArray = ^tPontArray; tPontArray = array[1..30000] of Tadat; : : : procedure IttKellNagyTomb(); var T : pPontArray; begin New(P); try T^[16].X:=5; // kell az a kis kalap! finally Dispose(P); end; end;
    Vagy még egyszerűbb a dinamikus tömb, az ugyanezt automatikusan csinálja:

    procedure IttKellNagyTomb(); var T : array of Tadat; begin SetLength(T,30000); T[16].X:=5; //mint minden más tömb, úgy használható end;
    szerk. úgy látom, kicsit lemaradtam, de hátha hasznos
    Mutasd a teljes hozzászólást!
  • Azt szeretném megkérdezni, hogy az első példádban a New(P) és Dispose(P) utasításokban P helyett nem-e T kell? Ha P kell, akkor mi a P.

    Illetve azt szeretném megkérdezni, hogy ha a halomban foglalok le memóriát akár az első pointeres módon, akár a második dinamikus tömb módon, akkor ez a memóriaterület összefüggő vagy sem? Mert nekem az adatok kiértékelésekor a tömb első elemétől végig kell mennem az utolsó elemig egyesével, és ha jól tudom, ez a memóriaelérés gyorsabb, ha a memóriában az adatok egymás után vannak. Vagy az, hogy a tömb elemei a memóriában szépen egymás után vannak, az csak akkor igaz, ha a tömb a stack memóriában van, és ha a halom memóriában, akkor ott már a fizikai memória különböző helyein lehet a tömb számára lefoglalt memória?

    Tehát voltaképp itt most arra irányul a kérdésem, hogy mikor fog gyorsabban a programkód lefutni.

    Egyébként a következőről van szó: van egy mikroszkópi képem, amin mikroszkópikus részecskék láthatók. Az ImageJ freeware program kiadja txt-be a részecskék területét pixelben, illetve súlypontjaik X és Y koordinátáit (illetve egyéb, számunkra lényegtelen adatot).
    Viszont nem adja ki, hogy az egyes részecskéknek és a hozzájuk legközelebb eső másik részecskének a súlypontja milyen távol van egymástól, ami viszont számunkra hasznos információval szolgálhat. Ezt a távolságot akarom kiszámoltatni minden egyes részecskére.
    Nem egy nagy program, úgyhogy ide is másolhatom. Az egész memóriás témát amiatt kezdtem el feszegetni, mert máskor is volt már képkiértékeléses problémám, és minél nagyobb a kép felbontása, annál gyorsabb módszereket kell alkalmaznom, mert real time képkiértékelést is kell csinálnom kb 10MP-es képen min 10 kép/s sebességgel, úgyhogy jó, ha már úgy kezdek bele, hogy a memóriakezelés és gyorsaság szempontjából legjobb módon. Autodidakta módon tanulom a programnyelveket, és sajnos a könyvek többsége az alapokat megtanítja, de ezeket a nüanszokat már nem.

    unit kepkiertekeles; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Label1: TLabel; OpenDialog1: TOpenDialog; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; type Tadat=record area:integer; X,Y:real; legkozelebbi_potty_sorszama:integer; legkozelebbi_potty_tavolsaga:real; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var inputfile:textfile; potty:array[1..25000] of Tadat; area:integer; mean, StdDev, Mode, Min, Max:byte; X,Y,XM,YM:real; pottysorszam:integer; sorszam:integer; tab:char; ujfilenev:string; fejlec:string; maxpottyszam, pottysorszam_vizsgalt, l_legkozelebbi_potty_sorszama:integer; l_min_tavolsag, l_tavolsag:real; outputfile:textfile; begin if Opendialog1.execute then begin Label1.Font.Color:=clRed; Label1.Caption:='Számolás folyamatban, kérem várjon!'; Label1.Refresh; tab:=#9; //ADATOK TOMB VÁLTOZÓBA Assignfile(inputfile, Opendialog1.FileName); reset(inputfile); readln(inputfile, fejlec); pottysorszam:=0; while not(eof(inputfile)) do begin pottysorszam:=pottysorszam+1; readln(inputfile, sorszam, area, mean, StdDev, Mode, Min, Max,X,Y,XM, YM); potty[pottysorszam].area:=area; potty[pottysorszam].X:=X; potty[pottysorszam].Y:=Y; end; closefile(inputfile); //SZAMITAS maxpottyszam:=pottysorszam; for pottysorszam_vizsgalt:=1 to maxpottyszam do begin l_legkozelebbi_potty_sorszama:=0; l_min_tavolsag:=1000000; for pottysorszam:=1 to maxpottyszam do begin if (pottysorszam_vizsgalt<>pottysorszam) then begin l_tavolsag:=sqrt(sqr(potty[pottysorszam_vizsgalt].X-potty[pottysorszam].X)+sqr(potty[pottysorszam_vizsgalt].Y-potty[pottysorszam].Y)); if (l_tavolsag<l_min_tavolsag) then begin l_min_tavolsag:=l_tavolsag; l_legkozelebbi_potty_sorszama:=pottysorszam; end; end; end; potty[pottysorszam_vizsgalt].legkozelebbi_potty_sorszama:=l_legkozelebbi_potty_sorszama; potty[pottysorszam_vizsgalt].legkozelebbi_potty_tavolsaga:=l_min_tavolsag; end; //EREDMENYEK FILEBA ujfilenev:=changefileext(changefileext(Opendialog1.FileName,'')+'_tav','.txt'); fejlec:=fejlec+tab+'Legkozelebbi_potty_sorszama'+tab+'MinTavolsag[pixel]'; assignfile(outputfile, ujfilenev); rewrite(outputfile); writeln(outputfile, fejlec); for pottysorszam:=1 to maxpottyszam do begin writeln(outputfile, pottysorszam, tab, potty[pottysorszam].area,tab,'255',tab,'0',tab,'255',tab,'255',tab,'255',tab, potty[pottysorszam].X:10:3,tab,potty[pottysorszam].Y:10:3,tab, potty[pottysorszam].X:10:3,tab,potty[pottysorszam].Y:10:3,tab, potty[pottysorszam].legkozelebbi_potty_sorszama,tab, potty[pottysorszam].legkozelebbi_potty_tavolsaga:10:3); end; closefile(outputfile); Label1.Font.Color:=clGreen; Label1.Caption:='KÉSZ!'; end; end; end.

    A form-on csak egy button1, egy opendialog1 megy egy label1 van mindössze.
    Mutasd a teljes hozzászólást!
  • potty:array[1..25000] of Tadat; 

    Kezdj el hasznalni dinamikus arrayokat!

    var potty:array of Tadat;

    ...

    Es amint tudod a meretet:
    setlength(potty, meret);

    Kesobb le tudod kerdezni a hosszat a length(potty)-el, az utolso elem indexet meg a high(potty)-el.

    Ezt a heap-en fogja lefoglalni neked a Delphi runtime EGY NORMALIS MEMORY managerrel, ahol gigabyte-ok elfernek. A Stack egyszeruen nem erre való.

    Tovabbi elonye, hogy ha megszunik az igy deklaralt array hatokore (ebben az esetben kilep a program ebbol a functbol), a delphi magatol felszabaditja, de te magad is felszabadithatod egy setlength(array,0)-val.
    Mutasd a teljes hozzászólást!
  • Valóban T kell a New() és Dispose() paramétereként, elírtam, elnézést!
    Mindkettő esetén lineáris az elérés, vagyis nem lassabb észrevehetően, mint a globális változóként létrehozott tömbnél.
    De a kódodat látva sokkal jobbat javasolok: a változóidat a TForm1-ben deklaráld (akár a private akár a public részben). Így nem a verembe kerül, tehát nincs ilyen méretprobléma. Valójában a halomba kerül a form-mal együtt, így az elérése is kényelmes. Egyetlen hátránya ennek, hogy az egész programfutás idejére foglalja a memóriát. Ha ezt nem szeretnéd, leginkább a dinamikus tömböt javaslom (a második példám). Ja igen, fontos: a dinamikus tömb esetén mindig [0..n-1] az index, nem indulhat 1-től!
    Mutasd a teljes hozzászólást!
  • Köszönöm a magyarázatokat. Dinamikus tömbről még nem hallottam eddig, ebből kifolyólag még nem is használtam, úgyhogy köszönöm az új információkat.
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd