Limited amounts of code lines in COFFEE?
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
Cinema 4D Version: 9.6
Platform: Mac OSX ;
Language(s) : C.O.F.F.E.E ;
I need to ask because I get a mysterious COFFEE error (14) Stack overflow.
In principe I have a coffee code in three blocks in one cof file (or COFFEE TAG, no difference).
One that gets information from the scene , works fine.
Second that use that information to stear an object, works fine
And a third block that stears about 25 other objects.
The problem is, all work fine using any two of the blocks.
I can activate any few lines in the third block and it also works.
I need block one, but can use either block 2 or 3 as well and there are no errors.
What I wonder, is there a limit of lines that COFFEE can use?
The complete code is 2100 lines.
it´s not a matter of code length, it´s a matter of memory getting on the stack. And this one cannot handle arbitrary amount of memory. It´s kind of a temporary memory for small allocations. And that´s pretty fast.
You must redesign your code. Put it into smaller pieces of functions. This should already help (stack variables are kept on the stack until you leave the function they were defined in, so then they should be automatically popped from the stack).
If you define all variables in one function, they all get on the stack at the same time. And if there are too many, the stack overflows. :)
Thanks, it helps. I was also given a link and read up on stacks ( in general)and see the problem.
Right now I have pretty much all variables "on hold" till the final line since it is a sort of real time behaviour dependent on hundreds of criteria changing per frame. The joy of "Re-do and Do it Right" :)
May I ask a fundamental question?
In the "code" below", does var B "leave" the stack by itself just by being within those brackets?
The "GetMyTag" and A I suppose must be in the stack all the way thru.
GetMyTags(obj,type)
{ get tag code}
main(doc,op)
var A = dataA;
var C = dataC;
var B = dataB;
code using A and B
result using A and B
code using A , C and B-result
result using A , C and B
I mean;
The "GetMyTag" and A and C I suppose must be in the stack all the way thru.
Yes (I hope). According to general C/C++/Java/COFFEE(?) scope rules, variables only exist (on the stack) within their designated scope. For something inside of brackets, the scope is limited to within them.
Variables declared in a method only exist while the method is being processed - something to think about when declaring variables in the main() method as they will exist until the end of plugin execution. So, yes, A anc C will be in the stack all the way thru.
Thanks. What I'm fighting with is to get as many "B" as possible.
That is variables that leave as soon as I don't need them.
I'm still on the edge of filling the stack and still need some more in the code.....
Even if most of the code are uniqe calculations per function there are a few similar ones that I tried putting in a Class, like the GetMyTag.
It didn't help at the first tries, rather it filled the stack sooner....
I need to keep re-designing, but there are s---loads of variables, all needed allmost all the way...lots of cross referenses.
I'm also tossing the idea of getting that last block into a second plugin,
but I'm not really sure how to read data from the first to the second when its not clear ID given from the first plugin, only calculations.
Would "SendMessage" to the document work somehow?
(Just took a very breif look at it in the SDK)
I don't know too much about the internal structure of COFFEE so this is mainly speculative (but based on most languages).
Basically, there are two types of memory allocation: static and dynamic. Static memory is what is compiled into a program and is local to the program's data segment. While the program is executing, Dynamic memory is what is allocated from the system heap to hold stacks and 'memory' structures (classes, arrays, and so on).
Stacks store 'activation frames' for functions which hold information about arguments and local variables for the function call. It is called a stack because it acts like a stack of cards - when a function is called, it creates an activation frame on the top of the stack (pushed). When the function returns, the activation frame is removed from the top of the stack (popped). Simply put, think of the stack as a shifting tower of function calls where at the bottom of the stack sits main(). As calls return, they are 'popped' off of the stack further and further down until eventually main() returns and the program exits.
Also, there are more volatile stack elements, such as your var B, which only exist within a context within the called function. This usually extends to anything inbetween {} including loops and conditionals.
Like main(), global variables and local main() variables are sitting on the stack until execution ends. They always exist.
A solution to these is to A) avoid global variables whenever possible and B) break down routines so that a series of functions are called and return in a way that local variables are partitioned judiciously only for the work for which they are needed and go away in a timely manner.
Another option is dynamical memory allocation which puts data in the heap rather than the stack. Here's where my understanding of COFFEE is lacking. When you new a class, one would expect the new class instance to be taken from the heap. Remember that there is a difference between a stack 'pointer' to the class and the class itself. The pointer only occupies as much stack as a memory address value requires while the class instance would be the sum of all of its member variables. The problem with COFFEE is that it doesn't have 'pointers'. One must assume that when you do this:
var object = new(myClass);
object is a local variable on the stack and a 'pointer' to the myClass instance and the myClass instance is in memory.
Thank you Robert for a very instructive explanation.
I've been starting from "scratch" in that I've made an empty "frame" plugin where I now lift in chunks of my code to get as many "B"'s and sub "B"'s as possible.
Carefully lifting up variables in the hierarchy in steps to make them as shortlive as possible.
I'll now later tonight if the "Stack Monster" will scream in my face again:)
The SDK states that the CarbageCan is emptied by itself, but would adding my own empying do any good? Is it even possible to empty it "mid code" or does it do its thing the last thing anyway?
I'll be back to tell how I'm doing.
GarbageCollection (gc()) is something more akin to Java. What this is is sort of a 'stack' for dynamically allocated memory. But it's not a stack and not a last-in, first-out ordered system like a stack. In this case, a separate thread checks for references to the allocated dynamic memory blocks to go to none and then it frees the no-reference memory blocks automatically. In other languages, like C/C++, you allocate the memory and then you have to free the memory specifically at some point - or it hangs around as a 'memory leak'. With a garbage collection system, this will not occur since once the memory is no longer referenced, it is freed.
Garbage collection has no effect on the stack as it is employed solely for dynamic memory allocations. For instance, if you do the:
and then, at some point later on, do:
object = NULL;
or the variable 'var object' goes out of scope; as long as it is the only reference to that particular myClass instance, the GC will eventually get around to freeing the memory. In other words, if you do this:
void MyFunc()
// do stuff to object
when MyFunc returns, var object is removed from the stack. This removes the only reference to the myClass instance created. Then the GC will free that myClass instance as it checks memory references and finds that there are none for this myClass instance.
If you did this:
var MyFunc1()
var objstillreferenced = MyFunc2();
return object;
then the myClass instance created and referenced by var object would continue to exist as long as var objstillreferenced exists (and so on). Let's say that var objstillreferenced is a global variable. Then the reference would persist until the end of the program execution or var objstillreferenced is set to NULL.
Sincere thanks Robert.
By shoe-horning, sqeezing, nitpicking and occasionaly simply banging my forehead on the table..........it works!
I haven't checked the headroom yet and I have a few more semi heavy lines
(variables that must be "far" apart) to put in that wasn't made yet. But there is hope now :)