mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 17:10:48 +00:00
Improve memory management debug functionality
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@37873 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
6f99460252
commit
dc4d18ba28
3 changed files with 203 additions and 202 deletions
|
@ -1,3 +1,12 @@
|
|||
2014-05-09 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSDebug.m:
|
||||
* Headers/Foundation/NSDebug.h:
|
||||
Add GSDebugAllocationRecordObjects()
|
||||
and deprecate GSDebugAllocationActiveRecordingObjects()
|
||||
so we can turn individual object tracking on and off.
|
||||
Move documentation from source to header.
|
||||
|
||||
2014-05-08 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Tools/gdomap.m: Fix ifdefs for MINGW to avoid fork relatred code.
|
||||
|
|
|
@ -59,7 +59,8 @@ extern "C" {
|
|||
* GSDebugAllocationClassList()
|
||||
* GSDebugAllocationList()
|
||||
* GSDebugAllocationListAll()
|
||||
* GSSetDebugAllocationFunctions()
|
||||
*
|
||||
* GSSetDebugAllocationFunctions()
|
||||
*
|
||||
* When the previous functions have allowed you to find a memory leak,
|
||||
* and you know that you are leaking objects of class XXX, but you are
|
||||
|
@ -69,8 +70,9 @@ extern "C" {
|
|||
* could slow down your system appreciably - use them only temporarily
|
||||
* and only in debugging systems):
|
||||
*
|
||||
* GSDebugAllocationActiveRecordingObjects()
|
||||
* GSDebugAllocationRecordObjects()
|
||||
* GSDebugAllocationListRecordedObjects()
|
||||
* GSDebugAllocationTagRecordedObject()
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
|
||||
|
@ -85,65 +87,148 @@ GS_EXPORT void GSDebugAllocationAdd(Class c, id o);
|
|||
GS_EXPORT void GSDebugAllocationRemove(Class c, id o);
|
||||
|
||||
/**
|
||||
* Activates or deactivates object allocation debugging.
|
||||
* Returns previous state.
|
||||
* This function activates or deactivates object allocation debugging.<br />
|
||||
* Returns the previous state.<br />
|
||||
* You should call this function to activate
|
||||
* allocation debugging before using any of the other allocation
|
||||
* debugging functions such as GSDebugAllocationList() or
|
||||
* GSDebugAllocationTotal().<br />
|
||||
* Object allocation debugging
|
||||
* should not affect performance too much, and is very useful
|
||||
* as it allows you to monitor how many objects of each class
|
||||
* your application has allocated.
|
||||
*/
|
||||
GS_EXPORT BOOL GSDebugAllocationActive(BOOL active);
|
||||
|
||||
/**
|
||||
* Returns the number of instances of the specified class
|
||||
* which are currently allocated.
|
||||
* <p>
|
||||
* Returns the number
|
||||
* of instances of the specified class which are currently
|
||||
* allocated. This number is very important to detect memory
|
||||
* leaks. If you notice that this number is constantly
|
||||
* increasing without apparent reason, it is very likely a
|
||||
* memory leak - you need to check that you are correctly
|
||||
* releasing objects of this class, otherwise when your
|
||||
* application runs for a long time, it will eventually
|
||||
* allocate so many objects as to eat up all your system's
|
||||
* memory ...
|
||||
* </p>
|
||||
* <p>
|
||||
* This function, like the ones below, returns the number of
|
||||
* objects allocated/released from the time when
|
||||
* GSDebugAllocationActive() was first called. A negative
|
||||
* number means that in total, there are less objects of this
|
||||
* class allocated now than there were when you called
|
||||
* GSDebugAllocationActive(); a positive one means there are
|
||||
* more.
|
||||
* </p>
|
||||
*/
|
||||
GS_EXPORT int GSDebugAllocationCount(Class c);
|
||||
|
||||
/**
|
||||
* Returns the peak number of instances of the specified class
|
||||
* which have been concurrently allocated.
|
||||
* Returns the peak
|
||||
* number of instances of the specified class which have been
|
||||
* concurrently allocated. If this number is very high, it
|
||||
* means at some point in time you had a situation with a
|
||||
* huge number of objects of this class allocated - this is
|
||||
* an indicator that probably at some point in time your
|
||||
* application was using a lot of memory - so you might want
|
||||
* to investigate whether you can prevent this problem by
|
||||
* inserting autorelease pools in your application's
|
||||
* processing loops.
|
||||
*/
|
||||
GS_EXPORT int GSDebugAllocationPeak(Class c);
|
||||
|
||||
/**
|
||||
* Returns the total number of instances of the specified class
|
||||
* which have been allocated.
|
||||
* Returns the total
|
||||
* number of instances of the specified class c which have been
|
||||
* allocated - basically the number of times you have
|
||||
* allocated an object of this class. If this number is very
|
||||
* high, it means you are creating a lot of objects of this
|
||||
* class; even if you are releasing them correctly, you must
|
||||
* not forget that allocating and deallocating objects is
|
||||
* usually one of the slowest things you can do, so you might
|
||||
* want to consider whether you can reduce the number of
|
||||
* allocations and deallocations that you are doing - for
|
||||
* example, by recycling objects of this class, uniquing
|
||||
* them, and/or using some sort of flyweight pattern. It
|
||||
* might also be possible that you are unnecessarily creating
|
||||
* too many objects of this class. Well - of course some times
|
||||
* there is nothing you can do about it.
|
||||
*/
|
||||
GS_EXPORT int GSDebugAllocationTotal(Class c);
|
||||
|
||||
/**
|
||||
* Returns a NULL terminated array listing all the classes
|
||||
* for which statistical information has been collected.
|
||||
* This function returns a NULL
|
||||
* terminated array listing all the classes for which
|
||||
* statistical information has been collected. Usually, you
|
||||
* call this function, and then loop on all the classes returned,
|
||||
* and for each one you get current, peak and total count by
|
||||
* using GSDebugAllocationCount(), GSDebugAllocationPeak() and
|
||||
* GSDebugAllocationTotal().
|
||||
*/
|
||||
GS_EXPORT Class* GSDebugAllocationClassList(void);
|
||||
|
||||
/**
|
||||
* Returns a newline separated list of the classes which
|
||||
* have instances allocated, and the instance counts.
|
||||
* If 'changeFlag' is YES then the list gives the number
|
||||
* of instances allocated/deallocated since the function
|
||||
* was last called.
|
||||
* This function returns a newline
|
||||
* separated list of the classes which have instances
|
||||
* allocated, and the instance counts. If the 'changeFlag'
|
||||
* argument is YES then the list gives the number of
|
||||
* instances allocated/deallocated since the function was
|
||||
* last called. This function only returns the current count
|
||||
* of instances (not the peak or total count), but its output
|
||||
* is ready to be displayed or logged.
|
||||
*/
|
||||
GS_EXPORT const char* GSDebugAllocationList(BOOL changeFlag);
|
||||
|
||||
/**
|
||||
* Returns a newline separated list of the classes which
|
||||
* have had instances allocated at any point, and the total
|
||||
* count of the number of instances allocated for each class.
|
||||
* This function returns a newline
|
||||
* separated list of the classes which have had instances
|
||||
* allocated at any point, and the total count of the number
|
||||
* of instances allocated for each class. The difference with
|
||||
* GSDebugAllocationList() is that this function returns also
|
||||
* classes which have no objects allocated at the moment, but
|
||||
* which had in the past.
|
||||
*/
|
||||
GS_EXPORT const char* GSDebugAllocationListAll(void);
|
||||
|
||||
/**
|
||||
* Starts recording all allocated objects of a certain class.<br />
|
||||
* Use with extreme care ... this could slow down your application
|
||||
* enormously.
|
||||
* DEPRECATED ... use GSDebugAllocationRecordObjects instead.
|
||||
*/
|
||||
GS_EXPORT void GSDebugAllocationActiveRecordingObjects(Class c);
|
||||
|
||||
/**
|
||||
* Returns an array containing all the allocated objects
|
||||
* of a certain class which have been recorded.
|
||||
* Presumably, you will immediately call [NSObject-description] on
|
||||
* them to find out the objects you are leaking.
|
||||
* Warning - the objects are put in an array, so until
|
||||
* the array is autoreleased, the objects are not released.
|
||||
* This function activates (or deactivates) tracking all allocated
|
||||
* instances of the specified class c.<br />
|
||||
* Turning on tracking implicitly turns on memory debug (counts)
|
||||
* for all classes (GSAllocationActive()).<br />
|
||||
* Deactivation of tracking releases all currently tracked instances
|
||||
* of the class (but deactivation of general counting does not).<br />
|
||||
* The previous tracking state as reported as the return value of
|
||||
* this function.<br />
|
||||
* This tracking can slow your application down, so you should use it
|
||||
* only when you are into serious debugging.
|
||||
* Usually, you will monitor your application by using the functions
|
||||
* GSDebugAllocationList() and similar, which do not slow things down
|
||||
* much and return * the number of allocated instances; when
|
||||
* (if) by studying the reports generated by these functions
|
||||
* you have found a leak of objects of a certain class, and
|
||||
* if you can't figure out how to fix it by looking at the
|
||||
* code, you can use this function to start tracking
|
||||
* allocated instances of that class, and the following one
|
||||
* can sometime allow you to list the leaked objects directly.
|
||||
*/
|
||||
GS_EXPORT BOOL GSDebugAllocationRecordObjects(Class c, BOOL newState);
|
||||
|
||||
/**
|
||||
* This function returns an array
|
||||
* containing all the allocated objects of a certain class
|
||||
* which have been recorded ... to start the recording, you need
|
||||
* to invoke GSDebugAllocationRecordObjects().
|
||||
* Presumably, you will immediately call [NSObject-description] on them
|
||||
* to find out the objects you are leaking. The objects are
|
||||
* returned in an autoreleased array, so until the array is deallocated,
|
||||
* the objects are not released.
|
||||
*/
|
||||
GS_EXPORT NSArray *GSDebugAllocationListRecordedObjects(Class c);
|
||||
|
||||
|
@ -153,6 +238,9 @@ GS_EXPORT NSArray *GSDebugAllocationListRecordedObjects(Class c);
|
|||
* with it (if any).<br />
|
||||
* If the object was not recorded, the method returns nil<br />
|
||||
* The tag is retained while it is associated with the object.<br />
|
||||
* If the tagged object is deallocated, the tag is released
|
||||
* (so you can track the lifetime of the object by having the tag
|
||||
* perform some operation when it is released).<br />
|
||||
* See also the NSDebugFRLog() and NSDebugMRLog() macros.
|
||||
*/
|
||||
GS_EXPORT id GSDebugAllocationTagRecordedObject(id object, id tag);
|
||||
|
|
250
Source/NSDebug.m
250
Source/NSDebug.m
|
@ -91,10 +91,6 @@ static void (*_GSDebugAllocationRemoveFunc)(Class c, id o)
|
|||
}
|
||||
@end
|
||||
|
||||
/**
|
||||
* This functions allows to set own function callbacks for debugging allocation
|
||||
* of objects. Useful if you intend to write your own object allocation code.
|
||||
*/
|
||||
void
|
||||
GSSetDebugAllocationFunctions(void (*newAddObjectFunc)(Class c, id o),
|
||||
void (*newRemoveObjectFunc)(Class c, id o))
|
||||
|
@ -116,18 +112,6 @@ GSSetDebugAllocationFunctions(void (*newAddObjectFunc)(Class c, id o),
|
|||
[uniqueLock unlock];
|
||||
}
|
||||
|
||||
/**
|
||||
* This function activates or deactivates object allocation debugging.<br />
|
||||
* Returns the previous state.<br />
|
||||
* You should call this function to activate
|
||||
* allocation debugging before using any of the other allocation
|
||||
* debugging functions such as GSDebugAllocationList() or
|
||||
* GSDebugAllocationTotal().<br />
|
||||
* Object allocation debugging
|
||||
* should not affect performance too much, and is very useful
|
||||
* as it allows you to monitor how many objects of each class
|
||||
* your application has allocated.
|
||||
*/
|
||||
BOOL
|
||||
GSDebugAllocationActive(BOOL active)
|
||||
{
|
||||
|
@ -138,72 +122,87 @@ GSDebugAllocationActive(BOOL active)
|
|||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function activates tracking all allocated instances of
|
||||
* the specified class c.<br />
|
||||
* This tracking can slow your
|
||||
* application down, so you should use it only when you are
|
||||
* into serious debugging. Usually, you will monitor your
|
||||
* application by using the functions GSDebugAllocationList()
|
||||
* and similar, which do not slow things down much and return
|
||||
* the number of allocated instances; when
|
||||
* (if) by studying the reports generated by these functions
|
||||
* you have found a leak of objects of a certain class, and
|
||||
* if you can't figure out how to fix it by looking at the
|
||||
* code, you can use this function to start tracking
|
||||
* allocated instances of that class, and the following one
|
||||
* can sometime allow you to list the leaked objects directly.
|
||||
*/
|
||||
void
|
||||
GSDebugAllocationActiveRecordingObjects(Class c)
|
||||
BOOL
|
||||
GSDebugAllocationRecordObjects(Class c, BOOL newState)
|
||||
{
|
||||
BOOL oldState = NO;
|
||||
unsigned int i;
|
||||
|
||||
GSDebugAllocationActive(YES);
|
||||
if (newState)
|
||||
{
|
||||
GSDebugAllocationActive(YES);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_classes; i++)
|
||||
{
|
||||
if (the_table[i].class == c)
|
||||
{
|
||||
[uniqueLock lock];
|
||||
the_table[i].is_recording = YES;
|
||||
oldState = (YES == the_table[i].is_recording) ? YES : NO;
|
||||
if (newState)
|
||||
{
|
||||
the_table[i].is_recording = YES;
|
||||
}
|
||||
else if (YES == oldState)
|
||||
{
|
||||
while (the_table[i].num_recorded_objects > 0)
|
||||
{
|
||||
int j = the_table[i].num_recorded_objects;
|
||||
|
||||
the_table[i].num_recorded_objects = --j;
|
||||
[the_table[i].recorded_objects[j] release];
|
||||
the_table[i].recorded_objects[j] = nil;
|
||||
[the_table[i].recorded_tags[j] release];
|
||||
the_table[i].recorded_tags[j] = nil;
|
||||
}
|
||||
}
|
||||
[uniqueLock unlock];
|
||||
return;
|
||||
return oldState;
|
||||
}
|
||||
}
|
||||
[uniqueLock lock];
|
||||
if (num_classes >= table_size)
|
||||
if (YES == newState)
|
||||
{
|
||||
int more = table_size + 128;
|
||||
table_entry *tmp;
|
||||
[uniqueLock lock];
|
||||
if (num_classes >= table_size)
|
||||
{
|
||||
int more = table_size + 128;
|
||||
table_entry *tmp;
|
||||
|
||||
tmp = NSZoneMalloc(NSDefaultMallocZone(), more * sizeof(table_entry));
|
||||
tmp = NSZoneMalloc(NSDefaultMallocZone(), more * sizeof(table_entry));
|
||||
|
||||
if (tmp == 0)
|
||||
{
|
||||
[uniqueLock unlock];
|
||||
return;
|
||||
}
|
||||
if (the_table)
|
||||
{
|
||||
memcpy(tmp, the_table, num_classes * sizeof(table_entry));
|
||||
NSZoneFree(NSDefaultMallocZone(), the_table);
|
||||
}
|
||||
the_table = tmp;
|
||||
table_size = more;
|
||||
if (tmp == 0)
|
||||
{
|
||||
[uniqueLock unlock];
|
||||
return NO;
|
||||
}
|
||||
if (the_table)
|
||||
{
|
||||
memcpy(tmp, the_table, num_classes * sizeof(table_entry));
|
||||
NSZoneFree(NSDefaultMallocZone(), the_table);
|
||||
}
|
||||
the_table = tmp;
|
||||
table_size = more;
|
||||
}
|
||||
the_table[num_classes].class = c;
|
||||
the_table[num_classes].count = 0;
|
||||
the_table[num_classes].lastc = 0;
|
||||
the_table[num_classes].total = 0;
|
||||
the_table[num_classes].peak = 0;
|
||||
the_table[num_classes].is_recording = YES;
|
||||
the_table[num_classes].recorded_objects = NULL;
|
||||
the_table[num_classes].recorded_tags = NULL;
|
||||
the_table[num_classes].num_recorded_objects = 0;
|
||||
the_table[num_classes].stack_size = 0;
|
||||
num_classes++;
|
||||
[uniqueLock unlock];
|
||||
}
|
||||
the_table[num_classes].class = c;
|
||||
the_table[num_classes].count = 0;
|
||||
the_table[num_classes].lastc = 0;
|
||||
the_table[num_classes].total = 0;
|
||||
the_table[num_classes].peak = 0;
|
||||
the_table[num_classes].is_recording = YES;
|
||||
the_table[num_classes].recorded_objects = NULL;
|
||||
the_table[num_classes].recorded_tags = NULL;
|
||||
the_table[num_classes].num_recorded_objects = 0;
|
||||
the_table[num_classes].stack_size = 0;
|
||||
num_classes++;
|
||||
[uniqueLock unlock];
|
||||
return oldState;
|
||||
}
|
||||
|
||||
void
|
||||
GSDebugAllocationActiveRecordingObjects(Class c)
|
||||
{
|
||||
GSDebugAllocationRecordObjects(c, YES);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -321,29 +320,6 @@ _GSDebugAllocationAdd(Class c, id o)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns the number
|
||||
* of instances of the specified class which are currently
|
||||
* allocated. This number is very important to detect memory
|
||||
* leaks. If you notice that this number is constantly
|
||||
* increasing without apparent reason, it is very likely a
|
||||
* memory leak - you need to check that you are correctly
|
||||
* releasing objects of this class, otherwise when your
|
||||
* application runs for a long time, it will eventually
|
||||
* allocate so many objects as to eat up all your system's
|
||||
* memory ...
|
||||
* </p>
|
||||
* <p>
|
||||
* This function, like the ones below, returns the number of
|
||||
* objects allocated/released from the time when
|
||||
* GSDebugAllocationActive() was first called. A negative
|
||||
* number means that in total, there are less objects of this
|
||||
* class allocated now than there were when you called
|
||||
* GSDebugAllocationActive(); a positive one means there are
|
||||
* more.
|
||||
* </p>
|
||||
*/
|
||||
int
|
||||
GSDebugAllocationCount(Class c)
|
||||
{
|
||||
|
@ -359,23 +335,6 @@ GSDebugAllocationCount(Class c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total
|
||||
* number of instances of the specified class c which have been
|
||||
* allocated - basically the number of times you have
|
||||
* allocated an object of this class. If this number is very
|
||||
* high, it means you are creating a lot of objects of this
|
||||
* class; even if you are releasing them correctly, you must
|
||||
* not forget that allocating and deallocating objects is
|
||||
* usually one of the slowest things you can do, so you might
|
||||
* want to consider whether you can reduce the number of
|
||||
* allocations and deallocations that you are doing - for
|
||||
* example, by recycling objects of this class, uniquing
|
||||
* them, and/or using some sort of flyweight pattern. It
|
||||
* might also be possible that you are unnecessarily creating
|
||||
* too many objects of this class. Well - of course some times
|
||||
* there is nothing you can do about it.
|
||||
*/
|
||||
int
|
||||
GSDebugAllocationTotal(Class c)
|
||||
{
|
||||
|
@ -391,18 +350,6 @@ GSDebugAllocationTotal(Class c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the peak
|
||||
* number of instances of the specified class which have been
|
||||
* concurrently allocated. If this number is very high, it
|
||||
* means at some point in time you had a situation with a
|
||||
* huge number of objects of this class allocated - this is
|
||||
* an indicator that probably at some point in time your
|
||||
* application was using a lot of memory - so you might want
|
||||
* to investigate whether you can prevent this problem by
|
||||
* inserting autorelease pools in your application's
|
||||
* processing loops.
|
||||
*/
|
||||
int
|
||||
GSDebugAllocationPeak(Class c)
|
||||
{
|
||||
|
@ -418,15 +365,6 @@ GSDebugAllocationPeak(Class c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns a NULL
|
||||
* terminated array listing all the classes for which
|
||||
* statistical information has been collected. Usually, you
|
||||
* call this function, and then loop on all the classes returned,
|
||||
* and for each one you get current, peak and total count by
|
||||
* using GSDebugAllocationCount(), GSDebugAllocationPeak() and
|
||||
* GSDebugAllocationTotal().
|
||||
*/
|
||||
Class *
|
||||
GSDebugAllocationClassList()
|
||||
{
|
||||
|
@ -450,16 +388,6 @@ GSDebugAllocationClassList()
|
|||
return ans;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns a newline
|
||||
* separated list of the classes which have instances
|
||||
* allocated, and the instance counts. If the 'changeFlag'
|
||||
* argument is YES then the list gives the number of
|
||||
* instances allocated/deallocated since the function was
|
||||
* last called. This function only returns the current count
|
||||
* of instances (not the peak or total count), but its output
|
||||
* is ready to be displayed or logged.
|
||||
*/
|
||||
const char*
|
||||
GSDebugAllocationList(BOOL changeFlag)
|
||||
{
|
||||
|
@ -553,15 +481,6 @@ _GSDebugAllocationList(BOOL difference)
|
|||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns a newline
|
||||
* separated list of the classes which have had instances
|
||||
* allocated at any point, and the total count of the number
|
||||
* of instances allocated for each class. The difference with
|
||||
* GSDebugAllocationList() is that this function returns also
|
||||
* classes which have no objects allocated at the moment, but
|
||||
* which had in the past.
|
||||
*/
|
||||
const char*
|
||||
GSDebugAllocationListAll()
|
||||
{
|
||||
|
@ -673,8 +592,8 @@ _GSDebugAllocationRemove(Class c, id o)
|
|||
if (j < the_table[i].num_recorded_objects)
|
||||
{
|
||||
for (k = j;
|
||||
k + 1 < the_table[i].num_recorded_objects;
|
||||
k++)
|
||||
k + 1 < the_table[i].num_recorded_objects;
|
||||
k++)
|
||||
{
|
||||
(the_table[i].recorded_objects)[k] =
|
||||
(the_table[i].recorded_objects)[k + 1];
|
||||
|
@ -699,13 +618,6 @@ _GSDebugAllocationRemove(Class c, id o)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function associates the supplied tag with a recorded
|
||||
* object and returns the tag which was previously associated
|
||||
* with it (if any).<br />
|
||||
* If the object was not recorded, the method returns nil<br />
|
||||
* The tag is retained while it is associated with the object.
|
||||
*/
|
||||
id
|
||||
GSDebugAllocationTagRecordedObject(id object, id tag)
|
||||
{
|
||||
|
@ -723,7 +635,7 @@ GSDebugAllocationTagRecordedObject(id object, id tag)
|
|||
for (i = 0; i < num_classes; i++)
|
||||
{
|
||||
if (the_table[i].class == c)
|
||||
{
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -750,16 +662,6 @@ GSDebugAllocationTagRecordedObject(id object, id tag)
|
|||
return AUTORELEASE(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns an array
|
||||
* containing all the allocated objects of a certain class
|
||||
* which have been recorded ... to start the recording, you need
|
||||
* to invoke GSDebugAllocationActiveRecordingObjects().
|
||||
* Presumably, you will immediately call [NSObject-description] on them
|
||||
* to find out the objects you are leaking. The objects are
|
||||
* returned in an array, so until the array is autoreleased,
|
||||
* the objects are not released.
|
||||
*/
|
||||
NSArray *
|
||||
GSDebugAllocationListRecordedObjects(Class c)
|
||||
{
|
||||
|
@ -801,7 +703,7 @@ GSDebugAllocationListRecordedObjects(Class c)
|
|||
}
|
||||
|
||||
tmp = NSZoneMalloc(NSDefaultMallocZone(),
|
||||
the_table[i].num_recorded_objects * sizeof(id));
|
||||
the_table[i].num_recorded_objects * sizeof(id));
|
||||
if (tmp == 0)
|
||||
{
|
||||
[uniqueLock unlock];
|
||||
|
@ -810,11 +712,11 @@ GSDebugAllocationListRecordedObjects(Class c)
|
|||
|
||||
/* First, we copy the objects into a temporary buffer */
|
||||
memcpy(tmp, the_table[i].recorded_objects,
|
||||
the_table[i].num_recorded_objects * sizeof(id));
|
||||
the_table[i].num_recorded_objects * sizeof(id));
|
||||
|
||||
/* Retain all the objects - NB: if retaining one of the objects as a
|
||||
side effect eleases another one of them , we are broken ... */
|
||||
#if !GS_WITH_GC
|
||||
/* Retain all the objects - NB: if retaining one of the objects as a
|
||||
* side effect releases another one of them , we are broken ... */
|
||||
for (k = 0; k < the_table[i].num_recorded_objects; k++)
|
||||
{
|
||||
[tmp[k] retain];
|
||||
|
@ -825,15 +727,17 @@ GSDebugAllocationListRecordedObjects(Class c)
|
|||
[uniqueLock unlock];
|
||||
|
||||
/* Only then we create an array with them - this is now safe as we
|
||||
have copied the objects out, unlocked, and retained them. */
|
||||
* have copied the objects out, unlocked, and retained them. */
|
||||
answer = [NSArray arrayWithObjects: tmp
|
||||
count: the_table[i].num_recorded_objects];
|
||||
count: the_table[i].num_recorded_objects];
|
||||
|
||||
#if !GS_WITH_GC
|
||||
/* Now we release all the objects to balance the retain */
|
||||
for (k = 0; k < the_table[i].num_recorded_objects; k++)
|
||||
{
|
||||
RELEASE (tmp[k]);
|
||||
[tmp[k] release];
|
||||
}
|
||||
#endif
|
||||
|
||||
/* And free the space used by them */
|
||||
NSZoneFree(NSDefaultMallocZone(), tmp);
|
||||
|
|
Loading…
Reference in a new issue