Re: [Seed7-users] Seed7 - question
Interpreter and compiler for the Seed7 programming language.
Brought to you by:
thomas_mertes
From: Thomas M. <tho...@gm...> - 2021-09-04 09:04:23
|
Hi Anders, You wrote: > Q1: > Should a local variable in a function always release the memory used for it, > after the function has ended? > Comment: I have seen that an application I have been programming seems to > expand its memory usage every time that a certain function is used. The > function in question is a recursive function and in each recursive call a > copy is taken of a rather large object, using the ::= operator. The object > is passed to the function through the parameter-list and it does not matter > how it is passed (as value or ref call). Regarding Q1: In Q1 you wrote that you are using the ::= operator (statement). The ::= operator should never be called explicit. Internally ::= is used to initialize variables, constants, value parameters and elements of arrays, structs and hashs. But it should never be called explicit. Sorry that the interpreter does not prohibit calling ::= explizit. The compiler does not even generate code for an explicit call of the ::= operator. Basically ::= is like a copy constructor with an additional destination parameter as left operand. There are two main differences between the ::= and the := operator: 1. The ::= operator can also be used to initialize the value of a constant (Calling it explicit totally subverts the concept of a const value). 2. The := operator assumes that the left operand (the destination) already has a legal value (so it might free data of the old value). The ::= operator just overwrites the left operand (the old value is lost and this might result in a memory leak). Nomally ::= is called implicit, when there is no previous legal value (this way there is no memory leak). So I guess that the memory leak from Q1 comes from the explicit use of the ::= operator. > Q2: > Should memory for removed array-elements be released? > Comment: I am using a global array with string elements. This array is used > for passing messages in the application. Each time a message is handled it > is removed from the array. However it seems that a small amount of memory is > leaking due to this. If I deliberately increase message passing the memory > leakage is increased. Regarding Q2: How do you measure the memory usage? There are some mechanisms that hinder the measurement of memory. - The run-time library of Seed7 maintains a cache of string values. The cache allows quick access to new strings without calling malloc(). - If something is appended to a string (with &:= ) more memory is requested than necessary (to avoid calling realloc() too often). - Free and non-free memory in the heap can be intermixed, such that it is not possible to give memory (that has been requested in blocks from the OS) back to the operating system. - On top of that the operating system also does not reclaim memory immediately. Can you create a small test program, that still has this memory leak. With such a test program I can examine what is going on. > Q3: > How do one use the reference-type and the ref_list types? > Comment: My intention here is to use a ref_list variable to store references > to different types objects. But I cannot get this to work.at all. Actually I > get an error even when I try to create a reference to an object. Are there > some good examples I could study? Regarding Q3: The types 'reference' and 'ref_list' are part of the Seed7 reflection API. It is not a reflection in the sense that a program can inspect (or change) its own code. But a program can parse another program and can access all the details of it via the reflection API. The Seed7 compiler works this way. Interpreter and compiler share the same program representation. A 'reference' points to an object in this program representation. In a compiled program the objects of the program representation just don't exist. I am sorry to say: A 'reference' is not intended to be used as some sort of generic pointer. Having a generic pointer that can point anywhere would also be against the philosophy of Seed7. You should consider using OO. You can use object orientation to refer to different stucts (which contain elements with different types). E.g.: -------------------- Start tst275.sd7 -------------------- $ include "seed7_05.s7i"; const type: genericStruct is sub object interface; const proc: doSomething (in genericStruct: aGeneric) is DYNAMIC; const type: structA is new struct var integer: number is 0; end struct; type_implements_interface(structA, genericStruct); const func genericStruct: generateA (in integer: number) is func result var genericStruct: newGenericStruct is structA.value; local var structA: new_structA is structA.value; begin new_structA.number := number; newGenericStruct := toInterface(new_structA); end func; const proc: doSomething (in structA: a) is func begin writeln(a.number); end func; const type: structB is new struct var string: stri is ""; end struct; type_implements_interface(structB, genericStruct); const func genericStruct: generateB (in string: stri) is func result var genericStruct: newGenericStruct is structA.value; local var structB: new_structB is structB.value; begin new_structB.stri := stri; newGenericStruct := toInterface(new_structB); end func; const proc: doSomething (in structB: b) is func begin writeln(b.stri); end func; const proc: main is func local var genericStruct: generic1 is structA.value; var genericStruct: generic2 is structA.value; begin generic1 := generateB("Life, The Universe, and Everything:"); generic2 := generateA(42); write("Answer to the Ultimate Question of "); doSomething(generic1); doSomething(generic2); end func; -------------------- End tst275.sd7 -------------------- As you can see a genericStruct can refer to a struct with an integer or to a struct with a string. A genericStruct is a reference to a struct. The value structA.value is used to initialize a genericStruct, but structA.value is actually never accessed or changed. Using these declarations for some generic reference looks heavy. But if you use OO as general concept the overhead will probably be less. BTW: This could not be done without structs as a struct value carries the information to decide which method should be used at run-time. > Q4: > Is it possible to create proper function pointers? > Comment: I manage to create function pointers to proc-functions without any > parameters. But that is rather pointless. Also in this case it would be > helpful to have some good examples to study. Regarding Q4: Variables and parameters of type 'proc' or 'func aType' are intended to be used to define the parameters of statements. For this purpose they do not need parameters themself. For the function pointers you have in mind this cannot be used (exept for the case without parameters). Originally object orientation has been introduced as a way to have function pointers in a structured way. You should try to refactor your problem to object orientation instead of using function pointers. In Seed7 enumeration types can be combined with object orientation. E.g.: -------------------- Start tst274.sd7 -------------------- $ include "seed7_05.s7i"; const type: testEnum is new enum ONE, TWO, THREE end enum; const proc: test (ONE, in integer: number, in string: stri) is func begin writeln("test(ONE, " <& number <& ", " <& literal(stri) <& ")"); end func; const proc: test (TWO, in integer: number, in string: stri) is func begin writeln("test(TWO, " <& number <& ", " <& literal(stri) <& ")"); end func; const proc: test (THREE, in integer: number, in string: stri) is func begin writeln("test(THREE, " <& number <& ", " <& literal(stri) <& ")"); end func; const proc: test (in testEnum: anEnum, in integer: number, in string: stri) is DYNAMIC; const proc: main is func local var testEnum: enumValue is ONE; begin for enumValue range testEnum do test(enumValue, rand(1, 10), "aTest"); end for; end func; -------------------- End tst274.sd7 -------------------- Keep in mind that using enums with OO is not the only way to use OO. There are plenty ways to do OO without enums. The above example is just near to what is considered as a proper function pointer. I hope this has helped you. If you have more questions, just ask. Regards. Thomas |