[comp.sys.mac.programmer] Object Pascal and memory management

alistair@minster.york.ac.uk (02/24/89)

Can anyone out there explain how Object Pascal objects are allocated in memory,
and the relationship to segementation?  I have a program which sometimes bombs
due, I suspect to memory problems.  I should say that I am NOT using MacApp.

An object is a handle, right.  So when if write:

type
  Tthing = object(Tobject)
		i : integer;
		procedure p;
			...
	   end;
{$S seg1}
procedure Tthing.p;
...
{$S seg2}

var
  thing : Tthing;
begin
  new(thing) 

New allocates some memory on the heap and thing is set as an indirect pointer to it.
What goes in that bit of memory: the code for Tthing (i.e. for Tthing.p) and/or space
for the instance variable i?  What if I call new for another Tthing object?  Surely
I don't need another copy of the code for Tthing.p, but do I get one anyway?  What
does dispose(thing) do?

And then... I have had to segment my program because the compiler began to complain
about segments >32K, but what does that mean in the context of objects?  Can I
unload a segment I have finished with by something like UnloadSeg(@thing.p) -
and what would it mean if I did? How would that work in relation to a dispose(thing)?

I hope someone out there is able and willing to help.  I did try getting the
answers from the Apple Developers' Group - the British version of APDA - and
they knew no more than me, and couldn't be bothered finding out.  As far as
I'm concerned they are a waste of time and I don't care who knows it.  (These
are - of course - NOT necessarily the views of my employers, blah blah blah)

siegel@endor.harvard.edu (Rich Siegel) (03/01/89)

In article <604330910.18716@minster.york.ac.uk> alistair@minster.york.ac.uk writes:
>Can anyone out there explain how Object Pascal objects are allocated in memory,

	In Lightspeed Pascal (and probably in MPW Pascal as well), an
OBJECT type is allocated as a handle in the heap; the first word of the handle
is an A5-relative offset to the class info proc, and the rest of the space,
I believe, is for the instance variables.

	It's important that the DECLARATION for an object type be in the
main segment (or in some other segment that won't be unloaded or moved around),
but the implementation of a method can be in any segment, as long as you
don't do anything like unload your caller's segment.

		--Rich



Rich Siegel
Staff Software Developer
THINK Technologies Division, Symantec Corp.
Internet: siegel@endor.harvard.edu
UUCP: ..harvard!endor!siegel
Phone: (617) 275-4800 x305

rick@Jessica.stanford.edu (Rick Wong) (03/01/89)

In article <604330910.18716@minster.york.ac.uk> alistair@minster.york.ac.uk writes:
>Can anyone out there explain how Object Pascal objects are allocated
>in memory, and the relationship to segementation?
>

You've come to the right place!

>
>New allocates some memory on the heap and thing is set as an indirect
>pointer to it.  What goes in that bit of memory: the code for Tthing
>(i.e. for Tthing.p) and/or space for the instance variable i?  What if
>I call new for another Tthing object?  Surely I don't need another copy
>of the code for Tthing.p, but do I get one anyway?  What does
>dispose(thing) do?
>

Only the space for the object's instance variables are allocated.  The code
is loaded in from your application's CODE resources when needed.  There is
at most one copy of the code in memory at any time, regardless of the number
of instances of Tthing.

Dispose(thing) should dispose the object by calling DisposHandle on the
object handle.  Rather than call dispose, you should use the standard
TObject interface and call thing.Free, which will give your object a chance
to clean up after itself and free any other things it may have allocated.

>
>And then... I have had to segment my program because the compiler began
>to complain about segments >32K, but what does that mean in the context
>of objects?  Can I unload a segment I have finished with by something
>like UnloadSeg(@thing.p) - and what would it mean if I did? How would
>that work in relation to a dispose(thing)?
>

UnloadSeg and dispose are completely unrelated.  Freeing an object only
releases the memory occupied by its instance variables (i.e., its handle).
The code will remain in memory until you call UnloadSeg on it.

Calling UnloadSeg in Object Pascal may be tricky.  I've never tried it
because MacApp does it for me automatically.  The call you give for it
(UnloadSeg(@thing.p)) doesn't make sense -- you have to pass it the address
of a procedure or function.  This is probably where you're running into
trouble, since I suspect you may be inadvertently passing the address of
some sort of method dispatching table.  To be safe, you should declare a
dummy normal Pascal procedure in each of your unloadable segments and use
that to unload them, e.g.:

	{$S Segment1}
	procedure StupidDummyRoutineForUnloadingSegment1;
	begin
	end;

. . . and in your main event loop:

	UnloadSeg(@StupidDummyRoutineForUnloadingSegment1);

Hope this was helpful.

Rick "No, it's Hair Pie" Wong
Courseware Authoring Tools Project, Stanford University
rick@jessica.stanford.edu

ech@pegasus.ATT.COM (Edward C Horvath) (03/01/89)

From article <532@Portia.Stanford.EDU>, by rick@Jessica.stanford.edu (Rick Wong):
> Calling UnloadSeg in Object Pascal may be tricky...

Calling UnloadSeg is downright dangerous until you have a better understanding
of how to segment your code.  Read the MPW Linker description, paying 
particular attention to the "new segment" commands.  Read the analogous parts
of your pascal manual.  Repeat as needed.  Now organize your program into
groups of related functions until all the groups are under 32K in size.
Finally, VERY CAREFULLY introduce UnloadSeg calls so that nobody ever tries
to UnloadSeg a segment FROM WHICH IT MIGHT BE CALLED.

Scott Knaster recommends a simpler approach, namely at one place, at the top
of your event loop, call UnloadSeg for every segment except CODE 1.  Oh, yeah:
make sure the event loop is in CODE 1!  While this approach is nowhere near
optimal, it's simple and hard to screw up.  Doing a proper job requires that
you truly understand the flow of your program.  (Is there anything like
'cflow' in MPW?)

If this sounds like a royal pain in the back of your lap, you're absolutely
right.  If you're writing a commercial application with rigid memory
constraints you will have to do it anyway.  Or hope that MacApp does it
right for you, but MacApp is not the Philosopher's Stone: it can only deal
properly with what it understands.

But if you're doing a something less life-and-death, you can just break the
code into segments wherever you please to get 'em all under 32K.  If you
like, mark all the CODE resources PreLoad with ResEdit, or use the Knaster
hack.  Repeat, I do NOT recommend this for anything which is going to ever
see the light of day, and for ghod's sake don't put MY name on it, but when
it doesn't matter why bother?

=Ned Horvath=