Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

BIG Memory Problems....

Posted on 2003-03-28
14
Medium Priority
?
217 Views
Last Modified: 2010-04-16
Helo,
im writing a simple raycasting engine, ive set up some memory in the program for a virtual screen which i flip to vga. it is all working fine, but after about a minute the program stops with error 200: stack overflow, i cant see why it would do this, as i am reusing most variable and reusing the memory for the screen by looping the program.
any ideas or solutions anyone?
thanks - DF
0
Comment
Question by:nislick
  • 5
  • 4
  • 2
  • +3
14 Comments
 
LVL 3

Expert Comment

by:lmikle
ID: 8227688
Check your code on a deep recursion.
If your program call any recursive procedure that on each step allocate a lot of memory (even if it is a local variables) on one of recursive call the heap will ending. and you got a Stack overflow error.

If you find procedure with deep recursion you have a 2 ways to solve your problem.

1st - replace recursion by loop.
2nd - allocate memory in a global heap.

Also chack that you release allocated memory in each call of recursive procedure.

For more detailed analisys please post you code here.
0
 
LVL 22

Expert Comment

by:grg99
ID: 8227846
Try printing out Memavail every time thru the main loop.
You may have a memory leak.

Also in raycasting it's not unusual to recur a whole lot.  Imagine two surfaces that are almost parallel.  You could really go very deep into recursion.

I would keep a recursion level count.  If it recurs more than N times (N = 5 to 10 is about right) then just ignore that point and return.  There's not much detail you're going to gain by recursing that much.


Regards,


grg99
0
 

Author Comment

by:nislick
ID: 8227927
ive provided most of my code here - i left out some bits where its just calculations, not recursion, tho there is some looping in creating the tables, using the same variable.
ive jsut started using mem procedures, im not sure how to set it globaly, or how to release it properly....
cheers heres the code;;; quite a bundle of mess, sorry bout that, have 2 tidy it up!

uses crt,gfx,cossin;
type    virtualvga = array[1..64000] of byte;  ** memory stuff**
        virtptr    = ^virtualvga;

const   ang_0=0;     ang_30=160;   ang_45=240;   ang_90=480;
        ang_180=960; ang_270=1440; ang_360=1920; ang_195=1040;
        incangle=0.1875;
        maxdistance=1000;
        horizon=100;       **middle of screen, centre view**
        grid: array[1..4,1..4] of byte=  **map - sorta**
        ((0,0,0,0)
         (0,0,0,0)
         (0,0,0,0)
         (0,0,0,0));

var     ystep,xstep:array[0..1920]of real;  ** for calctables**
        scaletable: array[0..319] of real;
        htable:array[0..9790]of integer;
       
        yrad,xrad: integer;   **distances for x+y rays**
        loop1,x,xpos,ypos,playerx,playery,angle,shortdist:integer;  ** general global variables**
        key:char;
        checkhit:boolean;

        virtscr:  virtptr;  ** memory stuff**
        vaddr: word;


procedure setmemory;   ** starts memory**
begin
     getmem(virtscr,64000);
     vaddr:= seg (virtscr^);
end;

procedure calctables;   **calculates tables for use in addin lengths + getting height for screen**

procedure check(x,y:real; ray:char);             **check if rays hit walls**
begin
     checkhit:=false;
If ray='x' then
   if (angle=ang_90)or(angle=ang_270) then checkhit:=true else
   if (x<=0)or(x>=576) then checkhit:=true;
   if (grid[round(x/64),round(y/64)])>0 then checkhit:=true;
** same for yray**
end;


function dist(x,y:real; ray:integer):integer; **find distance of ray to wall**

procedure putpixel(x,y:integer; colour:byte; where:word);   **draws to virtual screen**
begin
     mem[where:x+(y*320)]:=colour;
end;

procedure flip;                       **flips from virtual to vga screen**
begin
waitretrace;
     move(virtscr^,mem[vga:0],64000);
cls(vaddr,0);
end;

procedure drawscreen(x,h:integer);            **finds where to draw from and draws to virtaul screen*
var ty,by:integer;
begin
** find top of line and bottom of line then subtract each**
repeat
     putpixel(x,ty,72,vaddr);
     inc(ty);
until ty>=by; **repeats pixel after pixel until top reaches bottom** - is there another way around this?
end;


procedure xray;                  ** xray ends when hits wall**
var ynext:real;
    xposxray,yposxray:real;
begin
xposxray:=playerx;
yposxray:=playery;
ynext:=ystep[angle];
repeat

**adds/subtracts from xray length depending on angle and position**

check(xposxray,yposxray,'x');
until (checkhit=true);
     xrad:=dist(xposxray,yposxray,x);
end;


procedure yray;                  ** same as xray**
var xnext:real;
    xposyray,yposyray:real;
begin
xposyray:=playerx;
yposyray:=playery;
xnext:=xstep[angle];
repeat

**Adds/subtracts from yray length depending on angle and position**

check(xposyray,yposyray,'y');
until (checkhit=true);
     yrad:=dist(xposyray,yposyray,x);
end;

procedure calcview;            ****MAIN PROGRAM - 'REPEAT' IS MAIN LOOP, THEN AT END THERE IS RECURSION...***
var dx,dy:integer;
begin
angle:=angle-x;

if keypressed=true then key:=readkey;
case key of
     'q': exit;
     'd': begin cls(vga,0); angle:=angle+240; flag:=false; end;
end;

key:=#0;
x:=0;

repeat
if angle>ang_360 then angle:=angle-ang_360 else
if angle<ang_0 then angle:=angle+ang_360 else angle:=angle;
xray;
yray;

if xrad<yrad then shortdist:=xrad else
   if yrad<xrad then shortdist:=yrad else
      if xrad=yrad then shortdist:=xrad;

drawscreen(x,htable[shortdist]);

inc(x);
inc(angle);
if keypressed=true then key:=readkey;

until (x>=320)or(key='q')or(key='d')or(key='a')or(key='w')or(key='s')or(keypressed=true);

flip;

if key<>'q' then calcview;
end;

procedure freememory;                  **frees memory**
begin
     freemem(virtscr,64000);
end;

begin                  ** start of program**
clrscr;
x:=0;
playerx:=192;
playery:=384;
            calctables;
            setmemory;
angle:=ang_360;
            setmcga;
            calcview;
            settext;
            freememory;
end.
0
Receive 1:1 tech help

Solve your biggest tech problems alongside global tech experts with 1:1 help.

 
LVL 15

Expert Comment

by:VGR
ID: 8228235
as previously pointed out partially, stack overflow occurs when local variables are too big. This includes recursion when allocating local variables. I don't see anything like this in the code above (you use globals).

I think the problem is in DrawScreen, althought I can't prove it.

Have you tried going step by step while surveying MemTotal and MemAVail (if I remember well) - I know this is for the Heap, but anyway you can't really look at the stack unless you go down to the registers level in CPU window mode and quasi-debug your program.

You could pass it to Purify

Sorry to be of no help.

Well, actually, I may be os some help :D

This procedure should be rewritten :
procedure check(x,y:real; ray:char);             **check if rays hit walls**
begin
  {$B+}
    checkhit:=false;
If ray='x' then
  checkhit:=(angle=ang_90)or(angle=ang_270)
else checkhit:=(x<=0)or(x>=576);
  checkhit:=checkhit OR grid[round(x/64),round(y/64)]>0;
** same for yray**
  {$B-}
end;

0
 
LVL 15

Expert Comment

by:VGR
ID: 8228244
and excuse-me, but those types :
type    virtualvga = array[1..64000] of byte;  ** memory stuff**
       virtptr    = ^virtualvga;

don't seem to be used :/

I won't complain, because one single instance of this virtualvga thing would occupy the full DATA segment 8-)
(65520 if my memory is correct)

If ever you can't trace the problem, I suggest changing the data model towards the Heap, paying very good attention to New/Dispose pairs and logic.
0
 

Author Comment

by:nislick
ID: 8228687
please do...criticism is a good thing :), but those type values are used by - virtscr:  virtptr;  ** memory stuff**
       vaddr: word;
0
 

Author Comment

by:nislick
ID: 8228715
the virtscr variable points to the array and so doesnt use up the 64k allowed but uses 640k base memory.
any ideas on how to change the data model towards the heap, because i have no idea :¬|
0
 
LVL 15

Expert Comment

by:VGR
ID: 8229626
for instance :
in stead of :
type    virtualvga = array[1..64000] of byte;  ** memory stuff**
      virtptr    = ^virtualvga;
Var somevar : virtualvga; // 64000 bytes from DATA

you may do

Var somevar : virtptr;

begin
  // stuff
  somevar:=New(virtptr);
  // stuff
  Dispose(somevar);
end.


so in fact, that's what you're using already 8-)
0
 
LVL 50

Expert Comment

by:dbrunton
ID: 8230067
Try using the Turbo Pascal compiler directives as well.

In this case it should be

{$M stacksize, heapmin,heapmax}

stacksize is in range 1024 to 65520.  By default the stacksize is 16K but change it to 65520.  This will give you heaps of stack for recursion purposes.

I'd recommend you try

program whatever;
{$M 65520,0,655360}
uses crt,gfx,cossin;

and see how it runs.  (May want to change that heapmax down a little)

0
 
LVL 1

Accepted Solution

by:
Okey earned 150 total points
ID: 8248188
Ever thought about that Parameters and variables are allways transferred to stack and that every string-constant is passed in TP over Stack?
Pascal uses to address its Data for routines trough using the SS reg. what results in that all passed values are put onto stack or a pointer to them is put onto Stack.
Normally this space will be recovered by ending the routine, but when you do recursion then do it like this

     FUNCTION WITH_LOCALS_AND_PARAMS(VAR X,Y,Z:REAL;??:??);
      VAR A,B,C... : ????
      CONST .....
      ....
     
      VAR A,B,C... : ????
          x,y,z:REAL;
         RESULT:BOOLEAN;
      CONST .....
      ....

      PROCEDURE  WITHOUT_LOCALS_AND_PARAMS;
      Begin
       Your Code
      END.

Don't use Local Data use Global Data!
Don't use Parameters or transfer any values because they are eating stack like mad!

0
 
LVL 15

Expert Comment

by:VGR
ID: 8248773
sorry boy, but according to Master Wirth, a "properly written" recursive routine (function or procedure) uses ONLY parameter or local data.

That's also the only way to make it crystal-clear and to be sure it works with no "side effects" ;-)

Moreover, the Asker has no recursion in his/her program, so...
0
 
LVL 1

Expert Comment

by:Okey
ID: 8253049
To make recursive structure avoidable because of known problems the use of globalized Data will lead to functions representing the recursive-routine-heart and make it possible to avoid recursion!
0
 
LVL 15

Expert Comment

by:VGR
ID: 8253093
this is called "unrolling" a recursion. It's not always feasible, but always lead to ugly code 8-)

a well-written recursion is never a problem.
0
 

Author Comment

by:nislick
ID: 8263538
Cheers, found the problem was in the way i set up the recursion...first i removed the variables at the start of the procedure, then i changed the recursion into a while loop :)
0

Featured Post

Receive 1:1 tech help

Solve your biggest tech problems alongside global tech experts with 1:1 help.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Are you a startup company? Being a startup, you may be using shared hosting, or maybe even dedicated hosting. But have you ever given a thought to using cloud computing now? Yes, don’t be surprised, it is possible for startups to opt for cloud compu…
Don’ts and Dos are two important end products of software testing basics that a tester needs to regard. This article attempts to explain the principles of both.
this video summaries big data hadoop online training demo (http://onlineitguru.com/big-data-hadoop-online-training-placement.html) , and covers basics in big data hadoop .
As many of you are aware about Scanpst.exe utility which is owned by Microsoft itself to repair inaccessible or damaged PST files, but the question is do you really think Scanpst.exe is capable to repair all sorts of PST related corruption issues?
Suggested Courses

564 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question