Larry Sweet
01/14/2010 5:20 PM
post45265
|
Hello,
I have inherited several Photon Custom widgets and have a question with regard to freeing resources.
One of the custom widgets inherits from PtLabel and in it's defaults func has code like this: w->label.string =
calloc(80,1);
How does this memory get freed when the widget is destroyed. I understood that string resources are freed automatically
based on strlen() so wouldn't this code introduce a memory leak if the string copied in wasn't exactly 80 bytes in
length?
Also there are several customs widgets that add their own resources and use strdup() to set initial values. How does
this memory get freed?
Thanks for your help. This is my first exposure to custom widgets :-).
Larry
|
|
|
Thomas Haupt
|
Re: Photon Custom Widgets
|
Thomas Haupt
01/15/2010 4:18 AM
post45279
|
Re: Photon Custom Widgets
Hi Larry,
to my knowledge, ALLOC, STRALLOC, and ARRAY resources are freed automatically by the Photon library when the widget is
deleted. Any other allocated resources you'll need to free() yourself in the widget class' destruction method
(Pt_SET_DESTROY_F).
- Thomas
|
|
|
Larry Sweet
|
Re: Photon Custom Widgets
|
Larry Sweet
01/15/2010 8:36 AM
post45286
|
Re: Photon Custom Widgets
Thanks for the information. The code w->label.string = calloc(80,1) is setting the string field in the parent class
label. According to the Building Custom Widgets documentation (pg 132), this field is of type Pt_ARG_IS_STRING. On
page 41 it says that String Resources are allocated based on the value returned by strlen().
So, my question is, if when the widget is being destroyed how does it free this memory that was allocated? If it does
it based on the length of the string that is currently in the resource isn't this a potential memory leak.
In fact, if this is a STRING resource, as opposed to an alloc resource is it correct in the first case to be using
calloc?
Thanks for your help.
|
|
|
Thomas Haupt
|
Re: Photon Custom Widgets
|
Thomas Haupt
01/15/2010 9:32 AM
post45293
|
Re: Photon Custom Widgets
Hey Larry,
> On page 41 it says that String Resources are allocated based on the
> value returned by strlen().
Yes, when using the library's standard resource setting functions. If you are allocating yourself, it's up to you. You
just need to make sure that the pointer does in fact point to dynamically allocated memory and -if storing a string in
the allocated chunk- that the allocation will be sufficiently arge enough to hold the string. If you want to allocate
more than strlen(s)+1, or allocate less and clip the string - feel free.
> So, my question is, if when the widget is being destroyed how does
> it free this memory that was allocated? If it does it based on the length
> of the string that is currently in the resource isn't this a potential memory
> leak.
No. It uses standard malloc/free mechanisms behind the scenes (just like, e.g., strdup() does.) The heap management will
know how large each allocated piece is, you do not have to have that knowledge explicitly when free()ing the block.
> In fact, if this is a STRING resource, as opposed to an alloc resource is
> it correct in the first case to be using calloc?
See above - entirely your choice. Though I'd probably not use calloc, as that will fill the allocated buffer with 0s --
which will immediately afterwards be overwritten with your non-0 string content...
- Thomas
|
|
|
Larry Sweet
|
Re: Photon Custom Widgets
|
Larry Sweet
01/15/2010 10:15 AM
post45304
|
Re: Photon Custom Widgets
Hi Thomas,
Thank you for your reply. This custom widget building is all new to me so please allow me to ask for further
clarification.
Are you saying that regardless of resource type it is up to the developer to free memory if they obtain it via the
Standard C library as opposed to some Photon API?
Larry
|
|
|
Thomas Haupt
|
Re: Photon Custom Widgets
|
Thomas Haupt
01/15/2010 11:09 AM
post45311
|
Re: Photon Custom Widgets
Sorry, obviously a misexpression on my side.
No - whether or not you'll need to free() an allocated resource yourself does not depend on who did the allocation, but
rather on the type of resource / member. String, array, and alloc resources will be freed automatically. If you should
have other resources, or widget structure members not registered as resources, that are associated with dynamically
allocated memory, you'll have to do the free().
Or, put in very crude pseudo-code terms:
DestroyWidget( wgt ) {
for all resources r of wgt->class do {
switch ( r->type ) {
case STRING:
case ARRAY:
case ALLOC:
free( POINTER(wgt,r) );
}
}
}
- Thomas
|
|
|
Larry Sweet
|
Re: Photon Custom Widgets
|
Larry Sweet
01/18/2010 7:42 AM
post45376
|
Re: Photon Custom Widgets
Hi Thomas,
The string resources we are assigning are being set with straight assignment statements in the widget defaults function.
We are not using PtSetResources for these initial assignments and we don't have a destructor-cleanup function. We are
relying on the default Photon code.
How does the Photon library code know the difference between:
w->label.string = calloc(80,1);
and
w->label.string = "This is a string";
If it calls free() internally on the static string isn't this a problem?
Thanks.
Larry
|
|
|
Larry Sweet
|
Re: Photon Custom Widgets
|
Larry Sweet
01/19/2010 7:57 AM
post45459
|
Re: Photon Custom Widgets
Hi Thomas,
Still trying to understand the process ... any comments to my previous post?
Thanks.
|
|
|
Thomas Haupt
|
Re: Photon Custom Widgets
|
Thomas Haupt
01/22/2010 5:05 PM
post45817
|
Re: Photon Custom Widgets
Hey Larry,
sorry, was travelling & not monitoring this week.
To answer your first question,
> How does the Photon library code know the difference between:
> w->label.string = calloc(80,1);
> and
> w->label.string = "This is a string";
...it doesn't. It simply can't, just like any old C program can't - or only could at high costs and/or using some bad
hacks.
If your string resources are defined as Pt_ARG_IS_STRING and the default destructor method is used, then assigning a
constant string literal is at least an error - even if it didn't cause a visible /problem/ in your tests yet.
So, to initialize your string resources, please use malloc/calloc+strcpy, or strdup.
Cheers,
- Thomas
|
|
|
Larry Sweet
|
Re: Photon Custom Widgets
|
Larry Sweet
01/25/2010 8:10 AM
post45848
|
Re: Photon Custom Widgets
Thank you Thomas. That helps clear things up. Is there some where in the online documentation that explains this?
After reading the Widget Building Documentation it wasn't clear to me how the magic worked :-).
Now back to tracking memory leaks ....
I have a simple application with a window and one custom widget. A timer on the base window creates and destroys the
window every 500 msec.
I can watch with sin and see the memory increase slowly over time. Approximately 7 meg over 60 hours.
Any suggestions for tracking this down?
Thanks.
Larry
|
|
|
Larry Sweet
|
Re: Photon Custom Widgets
|
Larry Sweet
01/26/2010 12:44 PM
post45948
|
Re: Photon Custom Widgets
Weird ....
If I #ifdef out the code in the widget's default function the leak stops ...
Changing the size of the requested calloc'd memory from 80 to 1024 bytes seemd to have no effect on the size of the leak
....
In all cases it seems the memory usage jumps up in 8K chunks.
Defaults function is very simple:
w->date = NULL;
w->time = NULL;
w->label.string = calloc (80,1);
label.string is inherited from the PtLabel widget and we have no destroy function. Relying on the default destructor ..
.
????
|
|
|
Misha Nefedov
|
Re: Photon Custom Widgets
|
Misha Nefedov
01/26/2010 12:48 PM
post45952
|
Re: Photon Custom Widgets
if( w->label.string ) {
free( w->label.string );
}
w->label.string = calloc(...);
|
|
|
Larry Sweet
|
Re: Photon Custom Widgets
|
Larry Sweet
01/26/2010 2:25 PM
post45955
|
Re: Photon Custom Widgets
Interesting, based on previous posts I was under the impression that I shouldn't need to call free because the default
destructor would do that for Pt_Arg_String resources. Is it possible that the destroy function is not finishing before
I create the next version of the widget? In this case the pointer to the previously calloc'd memory would be lost and
thus exhibit the memory loss I am experiencing??? Also why the 8k jump? It's like it is the size for the previous
widget's data structures that have not been freed yet .... ???
|
|
|
Larry Sweet
|
Re: Photon Custom Widgets
|
Larry Sweet
02/08/2010 12:34 PM
post46813
|
Re: Photon Custom Widgets
Hi Misha,
Any feedback on my previous questions? Thanks.
Larry
|
|
|
Misha Nefedov
|
Re: Photon Custom Widgets
|
Misha Nefedov
02/08/2010 2:19 PM
post46831
|
Re: Photon Custom Widgets
1. The destructor code doesn’t track allocations in a special way. It simply saves the addresses of memory blocks in
the widget members. Your code was simply overwriting a member with a new value. This causes the old block to be lost.
The destructor will “clean-up” the last allocated block – which was yours, but not the original one. That is a leak.
2. Memory allocation routines request more memory from the system (when needed) in 8KB blocks.
|
|
|
Larry Sweet
|
Re: Photon Custom Widgets
|
Larry Sweet
02/08/2010 4:33 PM
post46861
|
Re: Photon Custom Widgets
Thank you for your response Misha. I understand point 2, but still don't understand point one.
Why wouldn't the destructor clean-up code finish before the pointer is reassigned in the defaults function?
My test program continually creates and destroys the window that the custom widget is in. Shouldn't the destruction
code finish execution before the next window and widget is created?
Thanks Larry
|
|
|
Misha Nefedov
|
Re: Photon Custom Widgets
|
Misha Nefedov
02/08/2010 5:07 PM
post46865
|
Re: Photon Custom Widgets
When you assign a new value to a member the previous value is lost. There is no destructor called when you assign– this
is “C”. The destructors are called when you change a member through libph, or when you destroy your widget, again
through libph.
|
|
|
Larry Sweet
|
Re: Photon Custom Widgets
|
Larry Sweet
02/08/2010 5:51 PM
post46866
|
Re: Photon Custom Widgets
Hello Misha,
My test application continually creates and destroys windows with the custom widget in it. i.e. create window with
custom widget, destroy window, create window with custom widget, destroy window etc.
I am expecting that destroying the previous window will clean up the allocated memory before my next window/custom
widget is created and its default function called which then allocates another chunk.
Larry
|
|
|
Larry Sweet
|
Re: Photon Custom Widgets
|
Larry Sweet
02/10/2010 7:51 AM
post47011
|
Re: Photon Custom Widgets
Good Morning Misha,
Any comments on my last post? Just trying to understand the process.
Thanks.
Larry
|
|
|
Misha Nefedov
|
Re: Photon Custom Widgets
|
Misha Nefedov
02/10/2010 11:12 AM
post47038
|
Re: Photon Custom Widgets
It depends on how you create and destroy widgets. Let’s say you use a timer widget (that is inside of your window)
callback to destroy the window. We can’t immediately free() window’s memory as it would cause a crash in the widget
library when it continues to process outstanding events/callbacks. When you destroy a widget it is not immediately
recycled: the widget is marked for destruction; some resources are recycled immediately some not, and later at some “
save” point the remaining parts get recycled.
Obviously in your case the recycling is done after you create a new widget. This is fine. If your app doesn’t leak
memory, eventually it will reach a “saturation” point – and won’t grow anymore.
|
|
|
Larry Sweet
|
Re: Photon Custom Widgets
|
Larry Sweet
02/11/2010 7:14 AM
post47109
|
Re: Photon Custom Widgets
Good Morning Misha,
Thank you very much for the explanation. This is exactly what I was looking for.
I believe it explains the behaviour we are experiencing in our application.
Thanks for your patience :-).
Larry
|
|
|
|