What does "live in the heap" mean? - objective-c

I'm learning Objectiv C, and I hear the term "live in the heap" constantly, from what I understand its some kind of unknown area that a pointer lives in, but trying to really put head around the exact term...like "we should make our property strong so it won't live in the heap. He said that since the property is private. I know it'ss a big difference It's pretty clear that we want to make sure that we want to count the reference to this object so the autorelease wont clean it (we want to "retain" it from what i know so far), but I want to make sure I understand the term since it's being use pretty often.
Appreciate it

There are three major memory areas used by C (and by extension, Objective C) programs for storing the data:
The static area
The automatic area (also known as "the stack"), and
The dynamic area (also known as "the heap").
When you allocate objects by sending their class a new or alloc message, the resultant object is allocated in the dynamic storage area, so the object is said to live in the heap. All Objective-C objects are like that (although the pointers that reference these objects may be in any of the three memory data areas). In contrast, primitive local variables and arrays "live" on the stack, while global primitive variables and arrays live in the static data storage.
Only the heap objects are reference counted, although you can allocate memory from the heap using malloc/calloc/realloc, in which case the allocation would not be reference-counted: your code would be responsible for deciding when to free the allocated dynamic memory.

Related

are objects in every stack-based-only VM allocated on heap [duplicate]

Every time when I initiate a list in java, I will do
List<Integer> list = new LinkedList<>();
I assume that this will allocate the list on heap. Wonder if there's anyway that I could allocate the list on stack?
All objects, including their individual attributes, are stored on the heap.
All local variables, and their arguments, are stored on the stack because they contain primitive values or references.
However, in special cases, the java virtual machine may perform escape analysis and decide to allocate objects (including your LinkedList) on a stack, but this normally doesn't happen and isn't a major concern.
As a general rule, if you allocate an object on a stack you will get a copy of the object when you call a function that refers to it. In contrast, if you allocate an object on the heap, when you pass the pointer to the object you will get a copy of the pointer (which points to the very same object on the heap.)
It is theoretically possible for JVM implementations to allocate objects on the stack, using "escape analysis." If it can be determined that a reference to a created object never leaks off the stack, a JVM could allocate it on the stack instead of the heap. The benefit of this would be to reduce garbage collection overhead; when the stack frame is exited, that memory could be immediately reclaimed. It might also boost speed because of the locality of reference.
Starting in Java 7, escape analysis was introduced in the Oracle's HotSpot Java runtime. With this enhancement, HotSpot may choose not to allocate stack-local objects that aren't modified; rather than allocating them on the stack, it deletes the allocation altogether. While this stops short of stack allocation, it does demonstrate that such things are permissible runtime optimizations.
There is no way for the Java programmer to directly control this behavior, however. It's an optimization performed by the JIT compiler. I'm not sure if the language specification would permit this sort of optimization at compile-time. It might, but I haven't studied it.

When to use dispatch_once versus reallocation? (Cocoa/CocoaTouch)

I often use simple non compile-time immutable objects: like an array #[#"a", #"b"] or a dictionary #{#"a": #"b"}.
I struggle between reallocating them all the time:
- (void)doSomeStuff {
NSArray<NSString *> *fileTypes = #[#"h", #"m"];
// use fileTypes
}
And allocating them once:
- (void)doSomeStuff {
static NSArray<NSString *> * fileTypes;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
fileTypes = #[#"h", #"m"];
});
// use fileTypes
}
Are there recommendations on when to use each construct? Like:
depending on the size of the allocated object
depending on the frequency of the allocation
depending on the device (iPhone 4 vs iMac 2016)
...
How do I figure it out?
Your bullet list is a good start. Memory would be another consideration. A static variable will stay in memory from the time it is actually initialized until the termination of the app. Obviously a local variable will be deallocated at the end of the method (assuming no further references).
Readability is something to consider too. The reallocation line is much easier to read than the dispatch_once setup.
For a little array, I'd reallocate as the first choice. The overhead is tiny. Unless you are creating the array in a tight loop, performance will be negligible.
I would use dispatch_once and a static variable for things that take more overhead such as creating a date formatter. But then there is the overhead of reacting to the user changing the device's locale.
In the end, my thought process is to first use reallocation. Then I consider whether there is tangible benefit to using static and dispatch_once. If there isn't a worthwhile reason to use a static, I leave it a local variable.
Use static if the overhead (speed) of reallocation is too much (but not if the permanent memory hit is too large).
Your second approach is more complex. So you should use it, if it is needed, but not as a default.
Typically this is done when the object creating is extreme expensive (almost never) or if you need a single identity of the instance object (shared instance, sometimes called singleton, what is incorrect.) In such a case you will recognize that you need it.
Although this question could probably be closed as "primarily opinion-based", I think this question addresses a choice that programmers frequently make.
The obvious answer is: don't optimize, and if you do, profile first - because most of the time you'll intuitively address the wrong part of your code.
That being said, here's how I address this.
If the needed object is expensive to build (like the formatters per documentation) and lightweight on resources, reuse / cache the object.
If the object is cheap to build, create a new instance when needed.
For crucial things that run on the main thread (UI stuff) I tend to draw the line more strict and cache earlier.
Depending on what you need those objects for, sometimes there are valid alternatives that are cheaper but offer a similar programming comfort. For example, if you wanted to look up some chessboard coordinates, you could either build a dictionary {#"a1" : 0, #"b1" : 1, ...}, use an array alone and the indices, take a plain C array (which now has a much less price tag attached to it), or do a small integer-based calculation.
Another point to consider is where to put the cached object. For example, you could store it statically in the method as in your example. Or you could make it an instance variable. Or a class property / static variable. Sometimes caching is only the half way to the goal - if you consider a table view with cells including a date formatter, you can think about reusing the very same formatter for all your cells. Sometimes you can refactor that reused object into a helper object (be it a singleton or not), and address some issues there.
So there is really no golden bullet here, and each situation needs an individual approach. Just don't fall into the trap of premature optimization and trade clear code for bug-inviting, hardly readable stuff that might not matter to your performance but comes with sure drawbacks like increased memory footprint.
dispatch_once_t
This allows two major benefits: 1) a method is guaranteed to be called only once, during the lifetime of an application run, and 2) it can be used to implement lazy initialization, as reported in the Man Page below.
From the OS X Man Page for dispatch_once():
The dispatch_once() function provides a simple and efficient mechanism to run an initializer exactly once, similar to pthread_once(3). Well designed code hides the use of lazy initialization.
Some use cases for dispatch_once_t
Singleton
Initialization of a file system resource, such as a file handle
Any static variable that would be shared by a group of instances, and takes up a lot of memory
static, without dispatch_once_t
A statically declared variable that is not wrapped in a dispatch_once block still has the benefit of being shared by many instances. For example, if you have a static variable called defaultColor, all instances of the object see the same value. It is therefore class-specific, instead of instance-specific.
However, any time you need a guarantee that a block will be called only once, you will need to use dispatch_once_t.
Immutability
You also mentioned immutability. Immutability is independent of the concern of running something once and only once--so there are cases for both static immutable variables and instance immutable variables. For instance, there may be times when you need to have an immutable object initialized, but it still may be different for each instance (in cases where it's value depends on other instance variables). In that case, an immutable object is not static, and still may be initialized with different values from multiple instances. In this case, a property is derived from other instance variables, and therefore should not be allowed to be changed externally.
A note on immutability vs mutability, from Concepts in Objective-C Programming:
Consider a scenario where all objects are capable of being mutated. In your application you invoke a method and are handed back a reference to an object representing a string. You use this string in your user interface to identify a particular piece of data. Now another subsystem in your application gets its own reference to that same string and decides to mutate it. Suddenly your label has changed out from under you. Things can become even more dire if, for instance, you get a reference to an array that you use to populate a table view. The user selects a row corresponding to an object in the array that has been removed by some code elsewhere in the program, and problems ensue. Immutability is a guarantee that an object won’t unexpectedly change in value while you’re using it.
Objects that are good candidates for immutability are ones that encapsulate collections of discrete values or contain values that are stored in buffers (which are themselves kinds of collections, either of characters or bytes). But not all such value objects necessarily benefit from having mutable versions. Objects that contain a single simple value, such as instances of NSNumber or NSDate, are not good candidates for mutability. When the represented value changes in these cases, it makes more sense to replace the old instance with a new instance.
A note on performance, from the same reference:
Performance is also a reason for immutable versions of objects representing things such as strings and dictionaries. Mutable objects for basic entities such as strings and dictionaries bring some overhead with them. Because they must dynamically manage a changeable backing store—allocating and deallocating chunks of memory as needed—mutable objects can be less efficient than their immutable counterparts.

Can I snapshot and restore memory of Objective-C object graph?

I'm designing a object persistent code.
IMO, memory snapshot is fastest, reliable and compact persistent method within a few limitation.
It's easy with C structs. I can layout all objects' memory layout manually. I can save all references as index of object collection. So reference is not a problem.
Anyway I want to try this with Objective-C objects. To do this, objects must be positioned in specific location of memory. So, if I can specify memory location of allocation, I can snapshot the memory. And when restoring, I can get an object at specific address.
Of course, all of these are machine-specific and needs many tricks, but it's fine to me.
The only problem is I don't know way to specify location of new Objective-C object. How can I do this?
Generally people use NSCoding and NSKeyedArchiver (or some custom subclass thereof). I think your C method would have worked before the 64-bit runtime, since the data part of objects was implemented using structs, but I think the new runtime's use of nonfragile instance variables would complicate matters. In any event, the program that loads the persistent objects still has to have the class definitions for them, either hard-coded or loaded via bundles.

What's the difference between abandoned memory and a memory leak?

Both are exactly the same thing, except that "abandoned memory" refers to a whole object graph leaked rather than just a single object. Right?
First, you need to understand the notion of a "memory object graph" or "application object graph" (or, simply, "object graph" as it applies to allocated buffers). In this case, "object" refers to any allocation in your application, be it an object or a simple malloc()ed buffer. The "graph" part if it is that any object can contain a reference to -- a pointer -- to other objects.
The "live object graph" of an application are all of the allocations that can be reached, directly or indirectly, from the various "roots" in the application. A "root" is something that, on its own, represents a live reference to an object, regardless of whether or not anything else explicitly references the root.
For example, global variables are roots; by referring to an object, a global variable, by definition, makes that object part of the app's live object graph. And, by implication, any objects that the object referred to by the global variable are also considered to be live; not leaked.
The same goes for the stack; any object referred to by any thread's live stack is, itself, considered live.
With this in mind, a leak and abandoned memory actually do have two distinct meanings.
Leak
A leak is a piece of memory for which there are no references to the allocation from any live object in the application's live object graph.
I.e. the memory is unreachable and, thus, there is no way that it can ever be referred to again (barring bugs). It is dead memory.
Note that if object A points to object B and object B points to A, but nothing in the live object graph points to either A or B, it is still a leak. If the B->A and A->B references are both retained references, you got yourself a retain cycle & a leak.
Abandoned Memory
Allocations that are in the app's live object graph but are no longer reachable due to application logic issues are considered abandoned, but not leaked.
For example, say you have a cache whose entries are instances of NSData that were downloaded from some URL where the URL contains a session ID in the URL (a common pattern) and that session ID + URL are used as the key to look up stuff in the cache. Now, say the user logs out, causing the session ID to be destroyed. If the cache isn't also pruned of all entries specific to that session ID, then all of those NSData objects will be abandoned, but not leaked as they can still be reached via the cache.
In reality, there is little use in making this strong of a distinction between the two save for that fixing either requires very different strategies.
Fixing a leak is to figure out where the extra retain came from (or where a missing call to free() might need to be inserted, in the case of a malloc() based leak). Since a detected leak cannot be reached from the live object graph, fixing a leak is really this straightforward.
Fixing abandoned memory can be considerably trickier for a couple of reasons.
First, the memory is still reachable from the live object graph. Thus, by definition, there is an algorithmic problem in your application that is keeping the memory alive. Finding and fixing that can often be much more difficult and potentially disruptive then fixing a mere leak.
Secondly, there might be non-zeroing non-retained weak references to the abandoned allocation. That is, if you figure out where to prune the strong references and make the allocation actually go away, that doesn't mean that your work is done; if there are any remaining non-zeroing weak references, they will now be dangling pointers and..... BOOM.
As Amit indicated, Heapshot Analysis is quite adept at finding both leaks, abandoned memory and -- quite important -- overall "Undesirable Memory Growth".
Not sure if there's a standard terminology, but there's also the possibility of having memory around which does have a reference, but will never be used. (The Heap Shot feature of the Leaks instrument can help track this down.) I call this "bloat" to distinguish it from a true leak. Both are wasted memory.
Abandoned memory are the memory leaks. Heapshot Analysis will help you to Find Undesirable Memory Growth. This is good article about that. http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/

NSString pointer: theoretical questions after study

I have questions about the NSString pointer. I wanted to get to the bottom of this and actually tried to create a theory to obtain full understanding based on multiple information retrieved from then net. Please believe me when I say that I have not been lazy, and I actually read a lot, but I was still left with uncertainties and questions. Can you please confirm / deny when good / wrong, and I've put additional questions and doubts which are indicated by (?).
Here we go:
If I consider this very basic example:
NSString *sPointer = [[NSString alloc]initWithString:#"This is a pointer"];
[sPointer release];
My starting point was: The compiler reserves RAM memory for a pointer type and this memory (which also has an own address) contains the memory address (hexadecimal - binary) of the memory where another variable is stored (where it points to). The actual pointer would take up about 2 bytes:
1) First some general issue - not necessarily linked to objective C. The actual questions about the NSString pointer will come in point 2.
A string is a "string of characters", where 1 character takes a fixed amount of memory space, let's say 2 bytes.
This automatically means that the memory size occupied by a string variable is defined by the length of the character string.
Then I read this on Wikipedia:
"In modern byte-addressable computers, each address identifies a single byte of storage; data too large to be stored in a single byte may reside in multiple bytes occupying a sequence of consecutive addresses. "
So in this case, the string value is actually contained by multiple addresses and not by a single 1 (this already differs from what I read everywhere) (?).
How are these multiple addresses contained in 1 pointer in reality? Will the pointer be divided into multiple addresses as well?
Do you know what component in a computer actually identifies and assigns the actual address "codes"?
And now my actual questions;
2) In my example, the code does 2 things:
It creates a pointer to the address where the string variable is stored.
It also actually saves the actual "String variable": #"This is a pointer", because otherwise there would be nothing to point to;
OK, my question; I wondered what really happens when you release the pointer [sPointer release]; are you actually releasing the pointer (containing the address), or are you also releasing the actual "string variable" from memory as well?
I have learned that when you delete the reference, the memory where the actual variable is stored will just be overwritten at the time the compiler needs memory so it does not need to be cleared at that time. Is this wrong?
If it is correct, why do they say that it's really important to release the NSString pointer for performance reasons, if you just release the pointer which will basically contain only a few bytes? Or am I wrong, and is the memory where the actual variable is stored in fact also cleared at once with the "release" message?
And finally also: primitive datatypes are not released, but they "do" take memory space at the moment of declaration (but not more than a common pointer). Why shouldn't we release them in fact? What prevents us from doing something like: int i = 5, followed by [i release]?;
I'm sorry - a lot of questions in 1 time! In practice, I never had problems with it, but in theory, I also really want to fully understand it - and I hope that I'm not the only one. Can we discuss the topic?
Thank you and sorry for the bother!
Maybe I'm wrong but I just read yesterday that pointers usually take 4 bytes. That answers none of your questions but you seem really interested in this so I figured I would mention it.
I think the source of your confusion is that you are confusing primitives with Objective-C classes. Objective-C classes (or objects to be exact, instances of classes) can accept messages (similar to method invocations in other languages). retain is one such message. This is why an Objective-C NSString object can receive the retain message but not a primitive like an integer. I think that's another one of your confusions. retain and release etc. are not Objective-C language constructs, they're actual messages (think methods) you send to objects. That is why they apply to Objective-C objects but not to primitives like integers and floats.
Another similar confusion is that what you read about how strings are stored has more to do with C-style strings, like char *name = "john". However, when you create a pointer to an NSString, that points to an NSString instance, which itself decides how to handle storing the actual string bytes/characters. Which may or not be the same way that C strings are stored.
data too large to be stored in a single byte may reside in multiple bytes occupying a sequence of consecutive addresses. " So in this case, the string value is actually contained by multiple addresses and not by a single 1 (this already differs from what I read everywhere) (?). How are these multiple addresses contained in 1 pointer in reality?
In C for example, the pointer would point to the address of the first character in the string.
OK, my question; I wondered what really happens when you release the pointer [sPointer release]; are you actually releasing the pointer (containing the address), or are you also releasing the actual "string variable" from memory as well?
You are sending the release message to the NSString instance/object. This is important to note to avoid further confusion. You are not acting upon the pointer itself, but upon what the pointer is pointing to, which is the NSString object. So you are not releasing the pointer itself. After sending the object the release method, if its reference count has reached 0, then it will handle deallocating itself by deallocating everything it stores, which I imagine includes the actual character string.
If it is correct, why do they say that it's really important to release the NSString pointer for performance reasons, if you just release the pointer which will basically contain only a few bytes?
So yeah, you're actually sending the release message to the string instance and it handles how to deallocate itself if it has to. If you were to simply erase the pointer so that it no longer points at the string instance, then you simply will no longer know where/how to access the data stored at that location, but it won't make it magically disappear, the program won't automatically know that it can use that memory. What you're hinting at is garbage collection, in which, simply put, unused memory will automatically be freed for subsequent use. Objective-C 2.0 does have garbage collection but as far as I know it's not enabled on iOS devices yet. Instead, the new version of iOS will support a feature known as Automatic Reference Counting in which the compiler itself takes care of reference counting.
Sorry if I didn't answer all of your questions, you asked a ton :P If any of my information is wrong please let me know! I tried to limit my answer to what I felt I did know.
"Or am I wrong, and is the memory where the actual variable is stored in fact also cleared at once with the "release" message?" The memory IS NOT CLEARED, but goes into the free memory pool, so that it does in fact reduce the memory print of the program. If you did not release the pointer you would continue to "hog" memory until you consume all the virtual memory available and crash not only your program but potentiality the system as well.
How are these multiple addresses contained in 1 pointer in reality?
Will the pointer be divided into multiple addresses as well? Do you
know what component in a computer actually identifies and assigns the
actual address "codes"?
From the perspective of the programmer (take note of this), the pointer on itself is usually a 4-byte number that represents the offset from start from the memory (32-bits, in 64-bit you can have addresses up to 8 bytes). The thing is that this pointers points to the start of whatever is being stored, and that's it.
In C for example, the original strings used a NULL (\0) terminated strings to identify when a string ended (Try doing a printf() on C with a non-zero ended string, and it will print whatever is in memory until it finds a zero). This of course is pretty dangerous, and one has to use functions like strncpy (notice the "n") indicating that you should manually input the number of chars from the offset until it ends.
A way to circumvent this is storing the used space in the start of the memory address, something like
struct
{
int size;
char *string;
}string;
That stores the size to prevent any issues. Objective-C and many other more abstract language implement in their own way how to handle memory. An NSString* is quite an abstract class to know what happens behind the scenes, it probably inherits all its memory managing from the NSObject.
The whole point I'm try to get is that a pointer contains the starting address, and you can jump from byte-to-byte from there (or jumps of a certain size), keeping in mind the total length of whatever you're storing to avoid doing nasty things like overflowing the stack memory (hence, the name of this site).
Now, how the computer gives this addresses is entirely up to the Operating System, and your logical memory address you use in all your programs is quite different from what the underlying implementation uses (physical memory address). Typically, you'll find that memory is stored in segmented units called "frames", and a used frame is called a "page". And the mapping in between physical and logical is done with a "[Page Table]"2.
As you can see, the software handles pretty much everything, but doesn't mean that there isn't hardware to support this, like the TLB, a cpu-level cache that holds recent memory addresses for quick access.
Also, please take my answer with a grain of salt, it's been a while since I studied these subjects.
OK, my question; I wondered what really happens when you release the
pointer [sPointer release]; are you actually releasing the pointer
(containing the address), or are you also releasing the actual "string
variable" from memory as well? I have learned that when you delete the
reference, the memory where the actual variable is stored will just be
overwritten at the time the compiler needs memory so it does not need
to be cleared at that time. Is this wrong? If it is correct, why do
they say that it's really important to release the NSString pointer
for performance reasons, if you just release the pointer which will
basically contain only a few bytes? Or am I wrong, and is the memory
where the actual variable is stored in fact also cleared at once with
the "release" message?
When you release, you're just decreasing the memory count of the object. What you mean is what happens when it's dealloced (when the count reaches zero).
When you dealloc something, you're basically saying that the space where it has been reserved it's now free to be replaced by anything else requesting memory (through alloc). The variable may still point to a freed space, and this causes problems (Read about dangling pointers and leaks).
The memory might be cleared, but there's no guarantees.
I hope this clears all the doubts, as all of them spawn from your confusion about memory freeing.
And finally also: primitive datatypes are not released, but they "do"
take memory space at the moment of declaration (but not more than a
common pointer). Why shouldn't we release them in fact? What prevents
us from doing something like: int i = 5, followed by [i release]?;
The thing is C has two main things going (actually, a lot more): The Heap that stores memory that has been requested with alloc (or malloc in C), and these require to be freed. And the Stack, which holds local variables, that die when the function/block ends (the stack pops the function call).
In your example, the variable i has been locally declared within its scope, and it's contined in the stack. Trying to peform a dealloc/free (also, the variable i won't respond to release, nor dealloc, as it's not an object) won't work, as is not the type of memory which requires to be freed.
I suggest you going back to C before trying to tackle what Objective-C does, because it's hard to have a clear idea how the imperative programming works with all the nice abstractions like release and dealloc.
For the sake of the forum, I will make a brief and simplified summary of your answers as a conclusion. Thanks to all of you for this extended clarification, the mist disappeared! Don't hesitate to react in case you want to add or rectify something:
Rectification: a pointer on the Mac takes 4 bytes of memory space and not 2.
The pointer *sPointer points to an instance of the NSString class and NOT directly to the memory where the chars are saved.
The NSString instance consists of a set of iVars in which there is a pointer iVar that points to memory allocated where the char variables that make up the string are stored (defined when using the initWithString: instance method).
[sPointer release]; The release message is not sent to the pointer itself, but to the instance of the NSString Object. You are not acting on the pointer itself, but on what the pointer is pointing to (!).
When sending the alloc message, the retain count of the NSString instance object is increased by 1. When sending a "release" message it doesn't mean that the concerned memory is literally being emptied, but it decreases the retain count by 1. When the retain count reaches zero, the compiler knows that the previously allocated memory is available again for re-use.
The way memories addresses are presented is decided by the operating system. The logical memory address used in programs is different from what the underlying implementation actually uses (physical memory address).
LOCAL variables (not necessarily primitive variables) are stored in the Stack memory (unlike objects instances who are stored in the Heap memory). What this means is that they will be destroyed automatically at the end of a function (they are automatically removed from the stack). More info on the memory constructs stack and heap can be found in several threads that clarify the use and difference in their own way. e.g.. What and where are the stack and heap? / http://ee.hawaii.edu/~tep/EE160/Book/chap14/subsection2.1.1.8.html
Before I answer the points, you start with a false premise. A pointer takes up more than 2 bytes on a non-16 bit system. On the Mac, it takes up 4 bytes for a 32 bit executable, and 8 bytes in a 64 executable.
Let me note that the following is not entirely accurate (for optimization and some other reasons, there are several kinds of internal representations of strings and the initXXX functions decide which is instantiated), but for the sake of use and understandingof strings, the explanation is good enough.
An NSString is a class (and a rather complicated one as well). A string, i.e. an instance of that class, contains some administrative ivars and one that is another pointer which points to a piece of allocated memory big enough to at least hold the bytes/code points that make up the string. Your code (the alloc method, to be precise) reserves enough memory to contain all the ivars of the object (including the pointer to the buffer) and returns a pointer to that memory. That is what you store in your pointer (if initWithString: doesn't change it -- but I won't go into that here, let's assume it doesn't). If necessary, initWithString: allocates the buffer large enough to hold the text of the string and stores its memory in the pointer for it, inside the NSString instance. So it is like this:
sPointer NSString instance buffer
+---------------------------+ +-----------------+ +------+
| addr of NSString instance | ----> | ivar | +-> | char |
+---------------------------+ | ivar | | | char |
| ivar (pointer) | --+ | char |
| ivar | | char |
| etc... | | char |
+-----------------+ | char |
| etc. |
+------+
In the case of a hard-coded, literal string like #"Hello", the internal pointer only points to that string, which is already stored in the program, in readonly memory. No memory has to be allocated for it, and the memory can't be freed either.
But let's assume you have a string with allocated contents. release (either coded manually, or invoked by an autorelease pool) will decrement the reference count of the string object (the so called retainCount). If that count reaches zero, your instance of the NSString class will be dealloced, and in the dealloc method of the string, the buffer holding the string text will be released. That memory is not cleared in any way, it is only marked as free by a memory manager, which means it can be re-used again for some other purpose.