mk79 wrote:The reality is a bit more complicated and it differs between SMSQ/E, QDOS and compiled programs. First of all "DIM A(15000)" is NOT equivalent to malloc. Variables live in the variable area, not on the heap. On SMSQ/E the variable area is allocated from the heap and can be fragmented, on QDOS it's part of the basic data area. IIRC the basic area must be one block and moves if it must be enlarged. If it cannot be enlarged because there is stuff in the way then it will fail.
To answer your question, heap granularity/alignment is almost always 8 bytes, but that is not your problem.
But who outputs "MAX HEAP ERROR"? I'm not aware of this error message and greping my hard drive for it comes up empty.
Sorry for the confusion so let me clarify. In reality I'm doing a malloc(30000) within Digital 'C" SE when executing a parsed DIM(15000)... the DIM statement is not SuperBASIC but the BASIC within the ZXSimulator (A ZX81 pseudo emulator I've been developing).
So I deduced I have about 30000 bytes of heap space left with the current incarnation of ZXSimulator. I tested this as follows: I reset the QL (BBQL 128 running JSU ROM) and then started the ZXSimulator executable (via exec) and then malloc'ed 30000 bytes -- I can do this via DIM A(15000) as each integer is worth 2 bytes. I then tried to malloc an additional 20 bytes and the call failed (i.e. it returned NULL which causes me to give the aforementioned "MAX HEAP ERROR"). Nothing else was run within ZXSimulator so no other memory besides the normal startup of the interpreter happened (mostly stuff on the stack).
So next I tested the following: again, I reset the QL and started ZXSimulator and with nothing else I executed the following sequence:
a = malloc(12928); /* by loading a ZX81 BASIC program whose size is 12925 -- I chunk in 64 byte blocks (I first deduce the file size and allocate rounded to nearest 64 bytes) */
b = malloc(12992); /* i.e. 12928 + 64 -- I added exactly 64 bytes via adding a REM statement, accounting for the line number and the internal EOL */
free (a);
c = malloc (13056); /* i.e. 12992 + 64 -- once again, added exactly 63 more bytes */
free (b);
Then ran loaded BASIC program within ZXSimulator through all its paces, which does a number of malloc and free calls for internal interpretation and it ran perfectly.
So this suggests that heap allocation via malloc is greater than 64 bytes because when 'a' is freed, if QL heap is only allocated in 8 byte chunks, then that blob that 'a' pointed to would be 12928 in size and could not support the malloc for the 'c' variable. So you'd have a contiguous free chunk of no more than 12928 followed by an allocated chunk of 12992 and when a request of 13056 is made, it should fail since there is only about 30000 in heap overall -- but it doesn't. This leads me to believe that the initial malloc for 'a' gave a size big enough to, after it's freed, be able to handle the call for 13056.
So I don't think the heap is in 8 byte alignments as that doesn't follow what is happening in the sample above and seems to suggest something bigger than 64 bytes (perhaps 128 bytes) of block space when supporting a memory request from the heap. Now it could be from Digital 'C' SE's malloc call that this is done but I would have thought the block sizing would come from the OS not the compiler and having Digital 'C' SE's malloc blocking things at 128 bytes would be terribly inefficient if you need to write code that does a lot of small allocations like say a database of linked list/btree items as an example. You would waste a ton of memory if you allocate 128 minimum for anything you did.
If, on the other hand, the QL heap sets aside 128 byte block sizes when a heap allocation request is made, that would not be wasteful as not all of it would be used. Say you ask for 1 byte of heap space via a malloc and (being say a fist request) the QL sets aside 128 bytes of that and then allocates 1 byte. If another 1 byte request is made it is made within that initial 128 block, and so on. This then helps the QL heap deal a bit better with fragmentation so that it keeps contiguous blocks longer for smaller allocation and free requests. That's why I'm wondering what the QL heap is doing.