[comp.sys.amiga.tech] Fonts and freeing memory

zupke@jato.Jpl.Nasa.Gov (Brian Zupke ) (01/07/90)

Howdy!  I'm working on a C program that loads a font from disk using
OpenDiskFont(), uses it with SetFont(), and then gets rid of it later with
CloseFont().  My problem is that each time I run my program, I lose around
3k-4k bytes of memory (very close to the size of the font on disk).  I've
tried numerous combinations of font functions (even RemFont()) and still
have this problem.  Does anyone know if there's a bug in the font functions,
or am I doing something wrong?

Thanks in advance.

--Brian

addison@pollux.usc.edu (Richard Addison) (01/08/90)

In article <2528@jato.Jpl.Nasa.Gov> zupke@jato.Jpl.Nasa.Gov (Brian Zupke (JPL Amiga Club Pres.)) writes:
>Howdy!  I'm working on a C program that loads a font from disk using
>OpenDiskFont(), uses it with SetFont(), and then gets rid of it later with
>CloseFont().  My problem is that each time I run my program, I lose around
>3k-4k bytes of memory (very close to the size of the font on disk).  I've
>tried numerous combinations of font functions (even RemFont()) and still
>have this problem.  Does anyone know if there's a bug in the font functions,
>or am I doing something wrong?
>
>Thanks in advance.
>
>--Brian

Well, you don't need to worry about it.  When the system gets low on memory,
it will automagically free the memory that is used for the font.

Now, if you _really_ want to get that memory back immediately, you can
request an impossibly large amount of memory with AllocMem().  This will
flush all unused resources from memory.  (This is one of the main reasons
that the documents keep telling you to close everything you open, so it
can keep track).

But again, I recommend that you avoid doing this.  After all, if your
program (on another one) needs this font again, it will save time if
it doesn't have to reload it.

BTW, try "loadwb -debug" sometime and look for the invisible menu to
the right of 'special'.  See 'flushlibs'?  Don't try "Debug" unless you
have a terminal connected to your serial port.

Richard Addison

root@ccave.UUCP (Juergen Hermann) (01/09/90)

In article <2528@jato.Jpl.Nasa.Gov> zupke@jato.Jpl.Nasa.Gov (Brian Zupke ) writes:
>Howdy!  I'm working on a C program that loads a font from disk using
>OpenDiskFont(), uses it with SetFont(), and then gets rid of it later with
>CloseFont().  My problem is that each time I run my program, I lose around
>3k-4k bytes of memory (very close to the size of the font on disk).  I've

You MUST use OpenFont() to look for resident fonts before ever calling
OpenDiskFont(). If not, the font is made resident over and over again, in
fact loosing memory for nothing.

So do something like

    if ((WinFont = (struct TextFont *) OpenFont (&ta)) == NULL &&
	    (WinFont = (struct TextFont *) OpenDiskFont (&ta)) == NULL) {
	Abort ("Can't open font\n");
    }

--
   //  Juergen Hermann		UUCP: ira.uka.de!smurf!ccave!root
 \X/   75 Karlsruhe 1, FRG	Fido: 2:241/2.1212@FidoNet

a464@mindlink.UUCP (Bruce Dawson) (01/15/90)

> root writes:
> 
> Msg-ID: <145@ccave.UUCP>
> Posted: 9 Jan 90 03:21:25 GMT
> 
> Org.  : Chameleon's Cave [JDCP 0.96]
> Person: Juergen Hermann
> 
> You MUST use OpenFont() to look for resident fonts before ever calling
> OpenDiskFont(). If not, the font is made resident over and over again, in
> fact loosing memory for nothing.
> 
> So do something like
> 
>     if ((WinFont = (struct TextFont *) OpenFont (&ta)) == NULL &&
>             (WinFont = (struct TextFont *) OpenDiskFont (&ta)) == NULL) {
>         Abort ("Can't open font\n");
>     }
> 
> --
>    //  Juergen Hermann          UUCP: ira.uka.de!smurf!ccave!root
>  \X/   75 Karlsruhe 1, FRG      Fido: 2:241/2.1212@FidoNet


     Are you sure about having to call OpenFont() to avoid losing memory?  I
have never seen that documented, and when I tried it just now (opened the same
font several times, closing it after each opening, checking for memory loss,
using OpenDiskFont() only) and I had no memory loss, except (of course) on the
first open.

.Bruce Dawson.

bevis@EE.ECN.PURDUE.EDU (Jeff Bevis) (01/16/90)

In article <145@ccave.UUCP>, root@ccave.UUCP (Juergen Hermann) writes:
>
>So do something like
>
>    if ((WinFont = (struct TextFont *) OpenFont (&ta)) == NULL &&
>	    (WinFont = (struct TextFont *) OpenDiskFont (&ta)) == NULL) {
>	Abort ("Can't open font\n");
>      }

Well, I wouldn't do that either, because you can't be sure what the compiler
is going to do with your code.  You've got two expressions hooked together
with a logical 'and' -- now which one will the final code try first?  The one
on the right?  Uh-oh.  This is better:

	If((WinFont=(struct TextFont *)OpenFont(&ta))==NULL)
	 {
	  If((WinFont=(struct TextFont *)OpenFont(&ta))==NULL)
	    Abort("Can't open font\n");
	 }

That way, OpenFont() will always go first.


+--------------------------------+--------------------------------------------+
| Jeff Bevis 		         | "But I don't like spam!"		      |
| bevis@en.ecn.purdue.edu	 | 	     Give me Amiga or nothing at all. |
+--------------------------------+--------------------------------------------+

a464@mindlink.UUCP (Bruce Dawson) (01/17/90)

     Ignoring the fact that OpenFont() is NOT needed before a call to
OpenDiskFont(), there is nothing wrong with the following code:

     if (!(winfont = (struct TextFont *)OpenFont(&ta)) &&
          !(winfont = (struct TextFont *)OpenDiskFont(&ta)))
               blah blah it didn't work.

     C _guarantees_ that the first expression will be evaluated first.
Furthermore, it guarantees that if the first expression fails, the second
expression will not be executed at all.  If you look at K&R, you will find some
programs that _depend_ on this for proper execution.  However, as has been
pointed out, from an Amiga point of view that code is bunk, because the call to
OpenFont() isn't necessary.

.Bruce.

kodiak@amiga.UUCP (Robert R. Burns) (01/17/90)

In article <145@ccave.UUCP> root@ccave.UUCP (Juergen Hermann) writes:
)You MUST use OpenFont() to look for resident fonts before ever calling
)OpenDiskFont(). If not, the font is made resident over and over again, in
)fact loosing memory for nothing.

False.  OpenFont() is not needed here.

OpenDiskFont() will use the memory version if no better version exists on disk.

For 1.3 & earlier, this means the disk is hit every time looking for that
"better match".  This disk hit may be what confused you.

For 1.4, if the match in memory is already as good as it can get, the disk
won't be hit.  To prepare for that, ensure that the ta_Style and ta_Flags
you set in the TextAttr are those from the AvailFonts result: not just the
ta_Name and ta_YSize.

- Kodiak
-- 
Bob Burns, amiga!kodiak						 _
	| /_  _|. _ |		   Commodore __			|_) _ |_  _ )'
	|<(_)(_)|(_\|<		    /\ |  ||| _` /\		|_)(_\| )(_\ |
	| \ Software		___/..\|\/|||__|/..\___			 Faith

louie@sayshell.umd.edu (Louis A. Mamakos) (01/17/90)

In article <9001161446.AA29551@en.ecn.purdue.edu> bevis@EE.ECN.PURDUE.EDU (Jeff Bevis) writes:
>>So do something like
>>
>>    if ((WinFont = (struct TextFont *) OpenFont (&ta)) == NULL &&
>>	    (WinFont = (struct TextFont *) OpenDiskFont (&ta)) == NULL) {
>>	Abort ("Can't open font\n");
>
>Well, I wouldn't do that either, because you can't be sure what the compiler
>is going to do with your code.  You've got two expressions hooked together
>with a logical 'and' -- now which one will the final code try first?  The one
>on the right? 


According to my K&R, first edition in Appendix A "C Reference Manual", 
section 7.11:

	7.11 Logical AND operator

		{\it logical-and-expression:
			   expression && expression}

	The && operator groups left-to-right. It returns 1 if boths its
	operands are non-zero, 0 otherwise.  Unlink &, && guarantees 
	left-to-right evaluation; moreover the second operand is not
	evaluated if the first operand is 0.

So the example code posted works just fine.

louie

mcafee@tallis.dec.com (Steve McAfee) (01/17/90)

In article <5125@amiga.UUCP>, kodiak@amiga.UUCP (Robert R. Burns) writes...
>In article <145@ccave.UUCP> root@ccave.UUCP (Juergen Hermann) writes:
>)You MUST use OpenFont() to look for resident fonts before ever calling
> 
>False.  OpenFont() is not needed here.
> 
>OpenDiskFont() will use the memory version if no better version exists on disk.
> 

Interesting because I've noticed a loss of about 4K bytes occaisonally and
this prompted me to run Dave Haynie's SETFONT a couple of times.  Sure enough
every time I do a SETFONT SIESTA 14 WINDOW I lose about 4K and flushing doesn't
help.  Here's the code fragment from Dave's c++ version:

      TextFont *font() {
         TextFont *f = OpenDiskFont(&sfattr);

         if (!f) f = OpenFont(&sfattr);
         if (!f) fail("Font \"%s\" not found\n",sfattr.ta_Name);
         return f;
      }

This also raises the question, if I SETFONT in a CLI window and then endcli
that window, is that font permanently in memory or did someone decrement
the appropriate counter somewhere?  Apparently not because I did this a
couple of times and flushing didn't get rid of them.  xoper shows me a
bunch of copies sitting out there.  I don't have c++ or I would fix this.
Are you out there Dave?

- steve mcafee

gregg@cbnewsc.ATT.COM (gregg.g.wonderly) (01/18/90)

From article <9001161446.AA29551@en.ecn.purdue.edu>, by bevis@EE.ECN.PURDUE.EDU (Jeff Bevis):
> Well, I wouldn't do that either, because you can't be sure what the compiler
> is going to do with your code.  You've got two expressions hooked together
> with a logical 'and' -- now which one will the final code try first?  The one
> on the right?  Uh-oh.  This is better:

C was designed by people who had more insight into reality than this.  Logical
expressions are guaranteed to evaluate from left to right so the original
code is indeed correct.  Your's is too, but changing it is not necessary to
get the desired behavior.

	i.e.


	if ((b = call_func_b ()) == NULL || (a = call_func_a(b)) == NULL) {
		
		/*  Do something, both didn't work. */

	}

	will call "call_func_a" if the first condition (call_func_b
	returning NULL) is false, but will not call "call_func_a" if
	"call_func_b" returns NULL.  This means that one can guarantee
	that the parameter to "call_func_a" will be the value returned
	from "call_func_b", and it will not be "NULL".

One of the nicest things about C is that the behavior of the compiler is
almost always defined for expression evaluation.  Excepting the classic
mistake of

	*p++ = *p & 0x7f;

which, is not guarateed to evaluate the *p on the right before the *p++
on the left of the assignment operator.

-- 
-----
gregg.g.wonderly@att.com   (AT&T bell laboratories)

bevis@EE.ECN.PURDUE.EDU (Jeff Bevis) (01/19/90)

In article <1990Jan17.013417.20587@haven.umd.edu>, louie@sayshell.umd.edu (Louis A. Mamakos) writes:
>
>According to my K&R, first edition in Appendix A "C Reference Manual", 
>section 7.11:
>
>	7.11 Logical AND operator
>
>		{\it logical-and-expression:
>			   expression && expression}
>
>	The && operator groups left-to-right. It returns 1 if boths its
>	operands are non-zero, 0 otherwise.  Unlink &, && guarantees 
>	left-to-right evaluation; moreover the second operand is not
>	evaluated if the first operand is 0.
>
>So the example code posted works just fine.
>
>louie

[red, embarrassed face omitted]

I have obviously been using memory-destructive drugs.  Indeed I was wrong...
and I apologize for spreading bogus myth.... I would rather change my previous
statement to the form of "using two if's instead of the && would be clearer
and less confusing" instead of what I did state.  In some languages, the 
statement in question would present a problem of ambiguity, but thanks to
K&R, not in C.

At any rate, I am *never* going to loan out my K&R reference again, for if I
hadn't, I would've looked this up first.... :-(


+--------------------------------+--------------------------------------------+
| Jeff Bevis 		         | "But I don't like spam!"		      |
| bevis@en.ecn.purdue.edu	 | 	     Give me Amiga or nothing at all. |
+--------------------------------+--------------------------------------------+

doug@xdos.UUCP (Doug Merritt) (01/22/90)

In article <9001182253.AA18421@en.ecn.purdue.edu> bevis@EE.ECN.PURDUE.EDU (Jeff Bevis) writes:
>
>I have obviously been using memory-destructive drugs.  Indeed I was wrong...
>and I apologize for spreading bogus myth.... I would rather change my previous
>statement to the form of "using two if's instead of the && would be clearer
>and less confusing" instead of what I did state.

I don't mean this to be a flame, but that's not true either. This construct
is called "short circuit evaluation", and is as much a hallmark of C
as are, say, increment operators like "++i". It is *not* considered unclear
to take advantage of this feature. Quite the opposite.

It's true that features of a language which are not universally used in other
languages can be confusing to new users of that language. But that doesn't
mean they should be avoided. One should, in general, write code that assumes
general fluency on the part of the reader, rather than trying to write code
which assumes that the reader is a novice in the language. Doing so would
mean wholly avoiding such language features, implying that there is something
wrong with using them. There is not.

As a matter of fact, this is an area in which C has been rather influential.
As with the "++" operator, the short circuit evaluation feature has been
adopted more and more widely in new languages. This is simply to stress
that it *is* a feature.

As with any design, one should not confuse novice usability (learning curve
issues) with expert usability. By analogy, the Amiga's multitasking features
have been confusing to learn to work with for programmers accustomed to
non-multitasking systems like the IBM PC and the C64, etc, but that
doesn't make those features bad. They were not confusing to programmers who
were already accustomed to multitasking environments, particularly those who
were used to message passing as well. It's just a question of which metaphors
one has previous familiarity with.
	Doug
-- 
Doug Merritt		{pyramid,apple}!xdos!doug
Member, Crusaders for a Better Tomorrow		Professional Wildeyed Visionary