duvalj@bionette.cgrb.orst.edu (Joe Duval) (10/02/90)
Hi, I am using Turbo C on a 386-20 with 1 Meg of RAM. I have a program that needs to read in data from a couple of <30K files and display it on the screen in a scrollable window. (I have the window stuff down). I am having a problem when I free up the space held by the two data file and the windows. And I have noticed that my program will completely hang if I try to free up one of the variables before the others. I have yet to get my program to work correctly. My question is does the order of mallocing and freeing data matter? Should whatever I malloc first be free'd last or the opposite? My program is showing inconsistency that seems to relate to the malloc'ing and free'ing I am doing. Here is how my program "works": /* the input will be straight ASCII text produced by another Turbo C program. I want to be able to read in the data for the two files and display it on the screen. */ # include <appropriate files> #define LINEDELTA 100 #define STRLEN 80 typedef char element[STRLEN] /* will be a line of a data file, lines can be up to 80 characters long */ int fillarray (char *filename, element *array) { /* fill the variable array with text from the file in filename realloc memory using LINEDELTA to increase the size of the array if the size of the array is not big enough */ } main () { element *data1, *data2; data1 = (element *) malloc (LINEDELTA*sizeof(element *)); data2 = (element *) malloc (LINEDELTA*sizeof(element *)); /* One of the files is usually about 20 times the size of the other. If I read in the smaller one first, the data in the smaller one gets trashed when I read in the data to the second one. What can I do to avoid that. things are fine if I read in the data for the larger one first (I may not know which of the two is the larger at run time) */ lines1 = fillarray ("test1", data1); lines2 = fillarray ("test2", data2); /* set up two windows. Uses a structure to keep track of lots of things about a window ala Al Stevens "Memory Resident Utilities, Screen I/O and Programming Techniques" Windows structures are kept in a linked list Display the data */ /* program gets through to here with no gliches usually :-) */ /* BUT it only will go so far through these lines, inconsistently crashing on one of these lines */ free (data1); free (data2); delete_window (window1); /* free's up the space occupied by this window */ delete_window (window2); /* and deletes it from the linked list */ } Thanks for reading and I'll be waiting for responses -- Joe Duval duvalj@bionette.cgrb.orst.edu Losing your temper generally represents the incipient stage of rectal- cranial inversion.
jeenglis@alcor.usc.edu (Joe English Muffin) (10/02/90)
duvalj@bionette.cgrb.orst.edu (Joe Duval) writes: >Hi, > I am using Turbo C on a 386-20 with 1 Meg of RAM. Which memory model? If it's small, tiny, or medium, that could be part of the problem. >My question is does the order of mallocing and freeing data matter? Should >whatever I malloc first be free'd last or the opposite? My program is showing >inconsistency that seems to relate to the malloc'ing and free'ing I am doing. No; you can free() mallocked areas in any order, as long as you don't free() the same thing twice. >Here is how my program "works": [ ... Much deleted ] >#define LINEDELTA 100 >#define STRLEN 80 >typedef char element[STRLEN] /* will be a line of a data file, lines can be up > to 80 characters long */ >main () >{ element *data1, *data2; > > data1 = (element *) malloc (LINEDELTA*sizeof(element *)); > data2 = (element *) malloc (LINEDELTA*sizeof(element *)); First, you really should check malloc's return value. It just might fail and return NULL. > /* One of the files is usually about 20 times the size of the other. If I > read in the smaller one first, the data in the smaller one gets trashed > when I read in the data to the second one. What can I do to avoid that. > things are fine if I read in the data for the larger one first (I may > not know which of the two is the larger at run time) > */ > lines1 = fillarray ("test1", data1); > lines2 = fillarray ("test2", data2); I would guess, that since fillarray() [description deleted] calls realloc() several times, the heap is probably getting too fragmented to allocate any more big chunks, and one of the realloc()s eventually fails. You could try using an exponentially increasing realloc() size instead of asking for (current_size + LINEDELTA) elements each time. That will decrease the number of realloc()s from O(n) to O(log n), which will probably help. Some good choices would be: current_size * 2 (O(2^n)) or current_size + last_size (O(Fib(n))). As for malloc() in general, here are the rule-of-thumb guidelines that I use: + Never malloc() lots of little items; malloc() off a big chunk and hand it out a piece at a time. If you need to free() the items individually, write your own free-list manager for each size item. (Or write a general-purpose one; that's what I did.) This saves malloc() overhead on each item allocated, and reduces fragmentation on many implementations of the allocator. + If you must malloc() small structures, malloc() the big stuff first. This helps fragmentation on most implementations of the allocator. + Don't use realloc() to dynamically resize things; use linked-lists or other dynamic structures. + If you must realloc(), then realloc() exponentially increasing sizes. This helps fragmentation on most implementations of the allocator. (Why "on most implementations of the allocator?" Malloc()/free() can be implemented in several ways; I have no idea which one Turbo C uses.) --Joe English jeenglis@alcor.usc.edu
6600m00n@ucsbuxa.ucsb.edu (Jihad 'R US) (10/05/90)
Your problem is this: // your line data1 = (element *) malloc(LINEDELTA * sizeof(element *)); // the line as is should be. data1 = (element *) malloc(LINEDELTA * sizeof(element)); // you need the size of the item you are using. otherwise, can you // say "trashed memory ????" Hope this helps rob (6600m00n@ucsbuxa.ucsbuxa)
empty@polari.UUCP (Terry Peterson) (06/13/91)
Under the following conditions, malloc() returns to main(), not to its caller, foo().-- Using TC V2.0 1) The penultimate caller, main() is compiled as a small model program 2) The caller of malloc(), foo(), is a library service compiled as a large model. Graphically, main() /* Part of a small model program */ | ------->foo() /* A library service compiled as a large model */ | -------> malloc() When malloc() is called from within foo() the compiler pushes both the CS register and the IP register on the stack as expected. However, malloc() does not return to the code segment where foo() resides, but rather to the code segment where main() resides! Disassembly of the code shows why: When malloc() is entered, foo()'s CS and IP are found in their proper place on the stack. However, when malloc() is done a "RET" instruction is executed, not RETF. Hence, only the IP is popped and the code "returns" to whatever segment malloc() happened to be mapped into. In this case, the segment that also contained main()'s code. How can I arrange to have malloc() return to the calling procedure, foo(), and NOT to main()? Thanks, in advance, /mtp
a_rubin@dsg4.dse.beckman.com (06/14/91)
In <4432@polari.UUCP> empty@polari.UUCP (Terry Peterson) writes: >Under the following conditions, malloc() returns to main(), not to its caller, >foo().-- Using TC V2.0 > 1) The penultimate caller, main() is compiled as a small model program > 2) The caller of malloc(), foo(), is a library service compiled as a > large model. >Graphically, > main() /* Part of a small model program */ > | > ------->foo() /* A library service compiled as a large model */ > | > -------> malloc() This is unlikely to work (as you reported in the section I did not quote). If any routines are compiled large model, all routines must be compiled large model or the linkages will not be correct. In MSC, this would probably produce an error message as both libraries SLIB.. and LLIB.. would be searched. (I haven't tried it, but it's still wrong.) You can, of course, explicitly declare everything you use in main as near. -- 2165888@mcimail.com 70707.453@compuserve.com arthur@pnet01.cts.com (personal) a_rubin@dsg4.dse.beckman.com (work) My opinions are my own, and do not represent those of my employer.