New command "IsMemoryID(*memoryID)
New command "IsMemoryID(*memoryID)
This may be a stupid suggestion, but I have a use for it.
I miss a IsMemoryID() function to check if a memory ID is still valid.
Unfortunately, it is not possible to use MemorySize(*MemoryID) for this check, because the program will crash if the MemoryID is not valid.
In my case, a procedure allocates memory independently and returns the MemoryID as a result. The calling process must release this memory on its own responsibility.
Since these functions are implemented in an OOP-framework (thanks to mk-soft), I would like to check this allocated memory and release it myself if necessary (because the user forgot to free the memory) when the related object will be destroyed.
Unfortunately this is only possible if I could check an invalid MemoryID without crashing the program.
I miss a IsMemoryID() function to check if a memory ID is still valid.
Unfortunately, it is not possible to use MemorySize(*MemoryID) for this check, because the program will crash if the MemoryID is not valid.
In my case, a procedure allocates memory independently and returns the MemoryID as a result. The calling process must release this memory on its own responsibility.
Since these functions are implemented in an OOP-framework (thanks to mk-soft), I would like to check this allocated memory and release it myself if necessary (because the user forgot to free the memory) when the related object will be destroyed.
Unfortunately this is only possible if I could check an invalid MemoryID without crashing the program.
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520, User age in 2024: 56y
"Happiness is a pet." | "Never run a changing system!"
"Happiness is a pet." | "Never run a changing system!"
Re: New command "IsMemoryID(*memoryID)
A memory ID is just a pointer to a given address in RAM. It's always going to be valid, even if that memory is freed.kurzer wrote:a IsMemoryID() function to check if a memory ID is still valid
Re: New command "IsMemoryID(*memoryID)
While this is true that the pointer is still valid (since it is just a regular integer variable), dereferencing (i.e. accessing) the memory certainly isn't.Dude wrote:A memory ID is just a pointer to a given address in RAM. It's always going to be valid, even if that memory is freed.kurzer wrote:a IsMemoryID() function to check if a memory ID is still valid
So @kurzer, memory ownership has always been an issue that has been a big problem in simpler languages such as PB and C because the compiler
doesn't offer any support for it. I'd recommend that you use one of two ways:
1) If you allocate the memory (e.g. in a library you wrote), then you also provide a way to free it.
2) Generally, I prefer it the other way around where the user takes the responsibility and passes a block of memory to your function.
Blog: Why Does It Suck? (http://whydoesitsuck.com/)
"You can disagree with me as much as you want, but during this talk, by definition, anybody who disagrees is stupid and ugly."
- Linus Torvalds
Re: New command "IsMemoryID(*memoryID)
Memory addresses can be re-used for new allocations once they have been freed. So even if the proposed IsMemoryID() function says that the memory is valid, you still don't know whether you can free it because there is no way to find out if it still references the same thing you once allocated. You could be freeing something that is still in use and have a random crash later.
quidquid Latine dictum sit altum videtur
Re: New command "IsMemoryID(*memoryID)
The safest way is to have only one memory pointer and set it to 0 when you release the memory.
sorry for my bad english
Re: New command "IsMemoryID(*memoryID)
Hello Shield,Shield wrote:1) If you allocate the memory (e. g. in a library you wrote), then you also provide a way to free it.
2) Generally, I prefer it the other way around where the user takes the responsibility and passes a block of memory to your function.
1) is the way I am going now. I also offer my own FreeMemory function in my object and store and track the memory address internally to check if the memory has already been released via my function.
2) I can't do it like that, because the user doesn't know how big the memory has to be. This is only decided within the function that allocates the memory. The function may have to perform a ReAllocate() several times. This depends on the data it have to process.
Yes, thats the way I do it now internally in my object, but this does not prevent the user from ignoring my FreeMemory() function and try to release the memory on his own.Josh wrote:The safest way is to have only one memory pointer and set it to 0 when you release the memory.
@Freak, okay, I understand the dilemma.freak wrote:Memory addresses can be re-used for new allocations once they have been freed. So even if the proposed IsMemoryID() function says that the memory is valid, you still don't know whether you can free it because there is no way to find out if it still references the same thing you once allocated. You could be freeing something that is still in use and have a random crash later.
However, I wonder why Fred didn't implemented the handling like with other PureBasic objects (e. g. Gadget).
For example, if you use ButtonGadget (#GadgetNr, x, y, width, heigth, text$[, flags]) you can either assign a unique gadget number yourself or use #PB_Any. Then the command itself returns a unique gadget number.
With this number you can perform an IsGadget() query without any problems.
So why not
Code: Select all
Allocatememory (#MemoryNr, Size)
Assuming you are using Allocatememory (1,1024), the command could immediately return the memory address as a result (because you delivered the unique memory number by itself -> 1).
If you use Allocatememory (#PB_Any, 1024), the command would return the unique memory number and a command
Code: Select all
MemoryAddress (MemoryNumber)
This would be close to the logical structure of the other PureBasic objects and therefore an
Code: Select all
IsMemory (memory number)
PS: I have thought about it several times and now I have to add the following information to my text above:
The problem with the ambiguous *MemoryID or MemoryNumber is only solved if AllocateMemeory() always returns a MemoryNumber by itself. With AllocateMemory(MemoryNumber, Size) only #PB_Any should be used as MemoryNumber (you could omit the first parameter, but the function must only return the MemoryNumber). PureBasic must then ensure that a new, previously not used MemoryNumber is always generated until the end of the program. The best way to do this is to always increase the memory numbers by one after every AllocateMemory() or FreeMemory() call until the exe quits.
Code: Select all
MyMem = Allocatememory(1024) ; returns the MemoryNumber 1 for example
Debug MyMem ; prints 1
Debug MemoryAddress(MyMem) ; returns for example $3674861, the real address of the memoryblock
Debug IsMemory(MyMem) ; will return #True
Freememeory(MyMem) ; frees the memory at address $3674861 (could return #True to show memory was successfully freed)
Debug IsMemory(MyMem) ; will return #False
MyMem = Allocatemomory(512) ; returns the MemoryNumber 2
MyMem2 = Allocatememory(1024) ; returns the MemoryNumber 3
MyNewMem2 = ReAllocatememory(MyMem2, 4096) ; still returns the MemoryNumber 3
Freememory(MyMem) ; could return #True to show memory was successfully freed
Debug IsMemory(MyMem) ; will return #False
Debug IsMemory(MyMem2) ; will return #True
Debug IsMemory(MyNewMem2) ; will return #True
Freememory(MyMem) ; could return #False to show memory number is not longer valid
Freememory(MyNewMem) ; frees the memory (could return #True to show memory was successfully freed
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520, User age in 2024: 56y
"Happiness is a pet." | "Never run a changing system!"
"Happiness is a pet." | "Never run a changing system!"
Re: New command "IsMemoryID(*memoryID)
It worked like this once upon a time. But it was much too cumbersome for simple memory allocations which is why it was changed.
How is this for a solution:
You say the use case is an Object that creates the memory and hands it out as a result which the user can free or the object should free on cleanup. So why not also provide a dedicated "Free"-function on the same object that the user must call to free the memory? Your object can then manage an internal list of memory blocks it handed out and remove any block that was freed with the "Free"-function. Then you know exactly which memory blocks must still be freed at the end. No more guessing involved. This solution would also make your implementation more flexible. Since both creation and freeing is handled within you object, you can change the implementation (for example switch the memory alloc with a linked list or array) without any need to change the code outside the object.
This example has the same problem: If IsGadget() tells you that the gadget is valid you can't just call FreeGadget() on it without knowing if the gadget is still the one you created. Remember: Your use case is that somebody else might have already called FreeGadget() on it (and a new one could have taken the same ID). #PB_Any numbers can be re-used as well!kurzer wrote:For example, if you use ButtonGadget (#GadgetNr, x, y, width, heigth, text$[, flags]) you can either assign a unique gadget number yourself or use #PB_Any. Then the command itself returns a unique gadget number.
With this number you can perform an IsGadget() query without any problems.
How is this for a solution:
You say the use case is an Object that creates the memory and hands it out as a result which the user can free or the object should free on cleanup. So why not also provide a dedicated "Free"-function on the same object that the user must call to free the memory? Your object can then manage an internal list of memory blocks it handed out and remove any block that was freed with the "Free"-function. Then you know exactly which memory blocks must still be freed at the end. No more guessing involved. This solution would also make your implementation more flexible. Since both creation and freeing is handled within you object, you can change the implementation (for example switch the memory alloc with a linked list or array) without any need to change the code outside the object.
quidquid Latine dictum sit altum videtur
Re: New command "IsMemoryID(*memoryID)
that's exactly how its working now, but what prevents the user from freeing the memory at his own using FreeMemory() instead of my free memory function? In this case the FreeMemory() within the destroy method of my object would crash the programm.
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520, User age in 2024: 56y
"Happiness is a pet." | "Never run a changing system!"
"Happiness is a pet." | "Never run a changing system!"
Re: New command "IsMemoryID(*memoryID)
@Freak: A quick question regarding #PB_Any with gadgets: will #PB_Any ever create a gadget number that I might have used for another gadget? Or does it check if the #PB_Any number is already in use for a gadget? Thanks.
Re: New command "IsMemoryID(*memoryID)
The gadget number you receive by creating a gadget with #PB_Any is the Pb intern handle for the gadget. That means, its a pointer to the memory, where Pb stores informations for this gadget. So I think, it can't be guaranteed, that this gadget number is used again.Dude wrote:@Freak: A quick question regarding #PB_Any with gadgets: will #PB_Any ever create a gadget number that I might have used for another gadget? Or does it check if the #PB_Any number is already in use for a gadget? Thanks.
sorry for my bad english
Re: New command "IsMemoryID(*memoryID)
So? That would be a bug by the user then. What prevents the user from making some other mistake that is not related to your object and crashing the program that way?kurzer wrote:that's exactly how its working now, but what prevents the user from freeing the memory at his own using FreeMemory() instead of my free memory function? In this case the FreeMemory() within the destroy method of my object would crash the programm.
As long as your gadget exists the number will not be reused. But once you free the gadget the number can be used again for another gadget.Dude wrote:@Freak: A quick question regarding #PB_Any with gadgets: will #PB_Any ever create a gadget number that I might have used for another gadget? Or does it check if the #PB_Any number is already in use for a gadget? Thanks.
quidquid Latine dictum sit altum videtur
Re: New command "IsMemoryID(*memoryID)
Therefore I use #PB_any whenever possible.
It works perfectly and undesirable collisions are safely avoided.
There cannot be a duplicate ID #PB_any because they are addresses.
Just as you can never get two identical addresses with AllocateMemory
It works perfectly and undesirable collisions are safely avoided.
There cannot be a duplicate ID #PB_any because they are addresses.
Just as you can never get two identical addresses with AllocateMemory
Re: New command "IsMemoryID(*memoryID)
Thats correct, but unfortunately you didn't understand what kind of problem I was referring to with my request. I didn't say there were address collisions.walbus wrote:Therefore I use #PB_any whenever possible.
It works perfectly and undesirable collisions are safely avoided.
There cannot be a duplicate ID #PB_any because they are addresses.
Just as you can never get two identical addresses with AllocateMemory
Nothing, but regarding to the "memory freed twice problem" PureBasic itself could prevent a crash like I already suggested. But as you already said, it was implemented once upon a time and Fred decided to remove this feature, so my feature request is useless at this point - c'est la vie.freak wrote:So? That would be a bug by the user then. What prevents the user from making some other mistake that is not related to your object and crashing the program that way?
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520, User age in 2024: 56y
"Happiness is a pet." | "Never run a changing system!"
"Happiness is a pet." | "Never run a changing system!"
Re: New command "IsMemoryID(*memoryID)
There can't be any IsMemoryID() function, because you can and must release simple and very fast the memory with FreeMemory() and then write it to Nirvana
Such a function therefore makes no sense
Such a function therefore makes no sense
Re: New command "IsMemoryID(*memoryID)
You can build a own Memory functions
Code: Select all
;-TOP
;
; Memory Debugging v0.4
CompilerIf #PB_Compiler_Debugger
#MemoryStop = 1
Global NewMap MemID()
Procedure MyAllocateMemory(Size, Flags, Proc.s)
Protected *mem
*mem = AllocateMemory(Size, Flags)
If *mem
MemID(Hex(*mem)) = *mem
Else
DebuggerWarning("AllocateMemory: Out Of Memory : Proc /" + Proc)
CompilerIf #MemoryStop : CallDebugger : CompilerEndIf
ProcedureReturn #False
EndIf
ProcedureReturn *mem
EndProcedure
Procedure MyFreeMemory(Memory, Proc.s)
If FindMapElement(MemID(), Hex(Memory))
FreeMemory(Memory)
DeleteMapElement(MemID())
ProcedureReturn #True
Else
DebuggerWarning("FreeMemory: Memory not exists : Proc /" + Proc)
CompilerIf #MemoryStop : CallDebugger : CompilerEndIf
ProcedureReturn #False
EndIf
EndProcedure
Procedure MyMemorySize(Memory, Proc.s)
If FindMapElement(MemID(), Hex(Memory))
ProcedureReturn MemorySize(Memory)
Else
DebuggerWarning("MemorySize: Memory not exists : Proc /" + Proc)
CompilerIf #MemoryStop : CallDebugger : CompilerEndIf
ProcedureReturn 0
EndIf
EndProcedure
Macro AllocateMemory(Size, Flags=0)
MyAllocateMemory(Size, Flags, #PB_Compiler_Module + "/" + #PB_Compiler_Procedure + "() - Line " + #PB_Compiler_Line)
EndMacro
Macro FreeMemory(Memory)
MyFreeMemory(Memory, #PB_Compiler_Module + "/" + #PB_Compiler_Procedure + "() - Line " + #PB_Compiler_Line)
EndMacro
Macro MemorySize(Memory)
MyMemorySize(Memory, #PB_Compiler_Module + "/" + #PB_Compiler_Procedure + "() - Line " + #PB_Compiler_Line)
EndMacro
CompilerEndIf
;- test
Procedure Main()
*mem1 = AllocateMemory(1024)
;*mem2 = AllocateMemory(2048)
Debug "Size 1: " + MemorySize(*mem1)
Debug "Size 2: " + MemorySize(*mem2)
Debug "Free 1: " + FreeMemory(*mem1)
Debug "Free 2: " + FreeMemory(*mem2)
EndProcedure : main()
Last edited by mk-soft on Sun Feb 11, 2018 9:07 pm, edited 1 time in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive