Garbage Collection in C/C++ versus Java
There is no Auto开发者_StackOverflow社区matic Garbage Collection in C/C++.
Assume that I wrote a simple program in C/C++ and created a single object. Assume that there are exactly 10 or extremely limited number of addresses for allocation.
I have a for loop running for 100 times inside which this single object is created every time the loop is run.
In Java, because there is Automatic Garbage collection, after a single loop is executed the address of the object is removed each time automatically.
Rough Example:
for(int i = 0; i < 100; i++)
{
Object o = new Object;
}
In C/C++ we have to manually remove the Object address inside the for loop. Do we have to reboot each time as well to properly remove the Object reference in C++?
For those who say that there are no problems deleting an object more than once in C++. from Wikipedia:
When an object is deleted more than once, or when the programmer attempts to release a pointer to an object not allocated from the free store, catastrophic failure of the dynamic memory management system can result. The result of such actions can include heap corruption, premature destruction of a different (and newly created) object which happens to occupy the same location in memory as the multiply deleted object, and other forms of undefined behavior.
The link: Manual Memory Management
So there IS a risk?
C++ doesn't have (built-in) garbage collection, but that doesn't mean you should let your dynamically allocated memory stay allocated forever. You can and should free it. The most basic way to that would be to free your object reference (or pointer, since this is C++) manually when you don't need it anymore:
for(int i = 0; i < 100; i++)
{
// Dynamically allocate an object
Object* o = new Object();
// do something with object
// Release object memory (and call object destructor, if there is one)
delete o;
}
If you allocated your object on the stack however, it always gets automatically released when it goes out of scope, and you don't have to wait for garbage collection to happen - it's always released immediately:
for(int i = 0; i < 100; i++)
{
// Create a new object on the stack
Object o = Object(); // Note we're not using the new keyword here.
// Do something with object
// Object gets automatically deallocated, or more accurately, in this specific
// case (a loop), the compiler will optimize things, so object's destructor
// will get called, but the object's stack memory will be reused.
}
This behavior of C++ stack values (automatic destruction when they go out of scope), which is awkwardly termed RAII (Resource Acquisition Is Initialization) allows for very nice things that Java just can't do. One of them is smart pointers, that allow dynamically allocated objects to be freed automatically just like their stack counterparts, and you can use sophisticated smart pointers to implement your own version of garbage collection if you want.
Another advantage of RAII is that finally-blocks are rarely necessary in C++: local variables that reference to a resource that should be freed immediately are usually allocated on the stack, and therefore get released automatically. No need for finally blocks here.
Practically speaking, when programming in C++ you'd usually put local variables on the stack (and get all the advantages of RAII without lifting a finger), unless you need to keep them alive for longer than that (e.g. you need to create an object and store a reference to it that stays alive when you leave the function that created the object). In that case, you can use pointers directly, but if you don't want to deal with manually deleting pointers and all the problems it can lead to, you'd usually use a smart pointer. A smart pointer is an object allocated on the stack, that wraps a 'dumb' (i.e. regular) pointer, and deletes the pointer when its destructor gets called. More advanced version of smart pointers can implement reference counting (so the pointed object will be released only when all smart pointers referencing it go out of scope) and even garbage collection. The standard library comes with two smart pointers: auto_ptr
and smart_ptr
(the latter is reference-counting, but some old compiler may not support it).
Java doesn't automatically remove the object at the end of each loop. Instead it waits until there is a lot of garbage and then goes through and collects it. Java makes no guarantees about how long it will be before the object is collected.
In C++, once the program has exited all resources are returned. You don't need to reboot (assuming a reasonable operating system) in order to make sure that resources are returned. Your operating system will take care of making sure that any resources your program didn't release get released when it is shutdown.
If you delete the object in C++, then its gone right then. you don't have to do anything else to recover the memory.
C++ certainly does have automatic storage duration; it just has other types of storage duration as well, and the ability to choose what is most appropriate.
In something like your example, you would use automatic storage:
for (int i = 0; i < 100; ++i) {
Object o;
// The object is automatically destroyed after each iteration
}
If the object is required to outlive the loop, perhaps because it is passed to another object to manage, then you would use smart pointers (the closest C++ equivalent to Java's references). Here are examples using auto_ptr
and shared_ptr
:
// some function that takes ownership of an object
void register(auto_ptr<Object> const & o);
void register(shared_ptr<Object> const & o);
for (int i = 0; i < 100; ++i) {
auto_ptr<Object> o(new Object);
register(o); // ownership may be transferred; our pointer is now null in that case
// The pointer is automatically destroyed after each iteration,
// deleting the object if it still owns it.
}
for (int i = 0; i < 100; ++i) {
shared_ptr<Object> o(new Object);
register(o); // ownership is shared; our pointer is still valid
// The pointer is automatically destroyed after each iteration,
// deleting the object if there are no other shared pointers to it.
}
In none of these cases do you need to manually delete the object; that is only necessary when dealing with raw object pointers which, in my opinion, should only be done when absolutely necessary.
C++ also has an advantage over Java here: destruction is always deterministic (that is, you know exactly when it happens). In Java, once an object is discarded, you do not know exactly when (or even if) the garbage collector will remove it. This means that, if the object manages a resource (such as a lock, or a database connection) that needs to be released after use, then it is up to the user of the object to manually release it. In C++, this can be done automatically in the destructor, making the class easier and less error-prone to use.
There is no Automatic Garbage Collection in C/C++.
False. C and C++ don't mandate automatic garbage collection, but it's available anyway (e.g., see the Boehm/Demers/Weiser collector).
In C/C++ we have to manually remove the Object address inside the for loop.
Again, false. In C or C++, we'd define the object using the automatic storage class, which would deterministically destroy the object:
for(int i = 0; i < 100; i++)
{
Object o;
}
Just for example, let's do a quick test, by defining Object
something like this:
struct Object {
Object() { std::cout << "Created an Object\n"; }
~Object() { std::cout << "Destroyed an Object\n"; }
};
For the loop above, this generates:
Created an Object
Destroyed an Object
Created an Object
Destroyed an Object
Created an Object
Destroyed an Object
[97 more repetitions of the same pattern removed ]
Do we have to reboot each time as well to properly remove the Object reference in C++?
No, of course not. The fundamental difference between C++ and Java in this respect is that in C++ the object destruction is deterministic, but in Java it's not. Just for example, in C++, the code above must follow exactly the prescribed pattern -- the body of the loop is a block, and the object must be created on entry to the block, and destroyed on exit from the block. In Java, you get no such assurance. It might only destroy the first object after it has allocated 10 or 20. The objects may be destroyed in any order, and there's not really a guarantee that any particular object will be destroyed at all.
That difference isn't always important, but certainly can be. In C++, it's used to support RAII (aka., SBRM -- stack bound resource management). This used to assure not only that memory is freed when no longer needed (i.e., the same thing Java's automatic garbage collector handles) but also that other resources (anything from files to widgets to network or database connections) are handled automatically as well.
If you have short lived objects and performance is critical (most of the time it is not) you can create a mutable object which is reused on each loop. This moves work from a per-iteration to per-loop.
List list = new ArrayList(); // mutable object.
for(int i = 0; i < 100; i++) {
list.clear();
// do something with the list.
}
// one list is freed later.
You can make the list a member field (meaning the mutable object might never be freed), which is fine, provided your class doesn't need to be thread safe.
Assuming you are on a typical operating system (Windows/Linux) - no you do not need to reboot. The OS will protect you via the Process/Virtual Memory structure.
Only your process will run out of memory. The OS will clean up after you when you process ends.
Running on many small embedded systems without an OS - yes you would crash or lockup the processor and require a reboot.
Adding to the already given answers, you can always write signal handlers, upon receiving which you can clean up the memory used by your process..
Normally the OS deallocate your program when you quit it. But some OS might not (I've seen that on a http://www.beck-ipc.com/en/products/sc1x/sc13.asp : RTOS didn't deallocate on exit so I ran out of memory after a couple of launch when I didn't deallocate all my objects, so yes I had to reboot). But most OS will clear/deallocate previously used programs (linux and windows does), so you shouldn't have to worry.
精彩评论