Quote
String storage in C64 BASIC
C64 BASIC uses 3 bytes for each string, which are stored in the 5 byte area of a simple variable located in the variable area or just takes exactly 3 bytes per element in case of a string array. This structure, called
string descriptor, consists of one byte containing the length of the string (hence the maximum of 255 bytes) and of two bytes forming a pointer to where the string is kept on the
string heap.
With statements such as,
10 A$="A STRING"
or strings that are filled by a
READ statement, the string descriptor points to program area where the statement is located so no space for the string itself has to be used. Other strings such as those built with an
INPUT statement, returned by string functions or those created by joining two or more strings together are stored in the area of memory between the
array area and the highest memory used by BASIC which is commonly known as the "string heap". The string pointer points to the start of this string.
Whenever a string that points to string heap is changed, its pointer is changed and the former string that was formerly referenced by this pointer is unused now on and becomes "garbage". To get the new string present on the string heap a new memory allocation will be made - even if the original string would be large enough to contain the new string. In case of statements like
A$=B$
where B$ already points to the string heap then rather setting A$ to point to the same string, a new copy of B$ is created (as a result of the generalized expression evaluation) on the string heap where A$ will be pointing to.
https://www.c64-wiki.com/wiki/Garbage_Collection Oddly enough - a potential answer in Garbage collection.
So, there is a solution here which might have diminishing returns very quickly. Every time I make a string in code, the descriptor points to the program, where it's already been stored. This gets large very quickly, but what I'm fuzzy on is - does it ever get UNallocated, for example, when exiting the scope of a GOSUB after RETURN by the garbage collector?
If it is, then the cost of pre-allocating often used strings is cheaper than defining them in the code (alike above). That is one direction I could take.
Sadly, I don't know what exactly I'm running out of - There are segments of memory dedicated to pointers and segments that contain their contents. Given the state of the program right now, I have have lot of strings defined in code.
What I think I need right now is a way to get the total size of a segment of memory (the string content, most likely) and give myself an in-game meter in order to watch.
In the midst of that little task - uh oh:
EDIT 2: ......................................Comments. The memory usage in a program includes the space taken by remarks. Wow. Just wow. After deleting some documentation, I was back under the limit and able to play. I have to delete and compress all of the comments in this file, and I know there are still thousands more lines to this program when it's done.
Well - that is pretty devastating. I'm not even a third of the way done.
EDIT3: Well, after some much-needed sleep - the answer lays within the ability to save program code space by swapping files and eliminating code from the main file to another file to be loaded and executed before popping back to the main loop. I know how to generally do this elsewhere, but not in BASIC V2 on the X16. How this is done without ruining the process or the program counter and making it as easy as functional programming - well - it feels a bit out of my league right now, but I'm not going to wimp out. I just need to understand how it's done cleanly within the loop of DRAW, INPUT, UPDATE, and returning to the main screen so the user can play.
I could use an example game that is using multiple files to manage its game state like this and how I could package it on a file system.