220 likes | 394 Views
Avoiding Resource Leaking. V1.2 dan@dmicsa.com , Dan Micsa, 2009. What is a resource?. A resource , or system resource , is any physical or virtual component of limited availability within a computer system. Every device connected to a computer system is a resource.
E N D
Avoiding Resource Leaking V1.2 dan@dmicsa.com, Dan Micsa, 2009
What is a resource? A resource, or system resource, is any physical or virtual component of limited availability within a computer system. Every device connected to a computer system is a resource. Every internal system component is a resource. Virtual system resources include files, network connections, memory areas, GDI objects, mutexes, etc.
What is their usage pattern? Acquire Use Release We get exceedingly good at acquiring and using resources but we often fail at releasing them back creating resource leaking/locking.
Why do we fail to release them? Because we are humans and we make mistakes. Because unexpected execution paths can occur (throwing exceptions for example). During software product life cycle resource can have dynamic usage. During software usage resource can have dynamic usage.
What is a Scope? A scope is an enclosing context where values and expressions are associated. Various programming languages have various types of scopes. The type of scope determines what kind of entities it can contain and how it affects them -- or semantics. Typically, scope is used to define the visibility and reach of information hiding. Scopes can: Contain declarations or definitions of identifiers; Contain statements and/or expressions which define an executable algorithm or part thereof; Nest or be nested.
What is the Stack? In computer science, a stack is an abstract data type and data structure based on the principle of Last In First Out (LIFO). Stacks are used extensively at every level of a modern computer system.
What is so special about Stacks? In C++, D, ADA(, C#), objects residing on the stack are automatically destroyed when the enclosing scope is exited. This includes the presence of exceptions their destructor is still called before the exception propagates. Objects defined in a scope are stored on the stack. Before leaving a scope each of them are automatic released by the language in the reverse order of their instantiation.
What is RAII? Resource Acquisition Is Initialization, often referred to by the acronym RAII, is a popular design pattern in several object oriented programming languages like C++, D and Ada. The technique, invented by Bjarne Stroustrup (the inventor of C++ language), ensures that when resources are acquired they are properly released by tying them to the lifespan of suitable objects: resources are acquired during the initialization of objects, when there is no chance of using them before the resource is available, and released with the destruction of the same objects, which is guaranteed to take place even in case of errors. In C++, objects residing on the stack are automatically destroyed when the enclosing scope is exited, including the case of exceptions; their destructor is called before the exception propagates.
What is RAII compliant? In C++ RAII is a fundamental paradigm. Any piece of code that is considered normal C++ must be RAII compliant. In conclusion any object need to be in a valid and known state at initialization and must clean up (release resources) after itself at destruction. A valid state doesn’t necessary means to acquire all the required resources at initialization time. Resource acquisition can be delayed and done as need it. However a C++ class it is expected to clean up after itself by default.
A RAII example class MutexHolder { private://redundand. It is by default private. Void Lock();{…} Void UnLock(){…} friend class AutoLockUnlock;//the only way to use this class is via its friend! }; class AutoLockUnlock { MutexHolder& mutexHolder; AutoLockUnlock(const AutoLockUnlock&);//disable copy construction. Is not implemented! AutoLockUnlock & operator=(const AutoLockUnlock&);//disable assignment. Is not implemented! public: explicit AutoLockUnlock(MutexHolder& mutexHolder_): mutexHolder(mutexHolder_) {mutexHolder.Lock();}//Acquiring in constructor. ~AutoLockUnlock(){mutexHolder.UnLock();}//Releasing (automatic) in destructor }; Void F() { static MutexHoldermutexHolder; //Create a mutual exclusion object AutoLockUnlockautoLockUnlock(mutexHolder); … }//Automatic unlock the mutex called from AutoLockUnlock destructor
All STL types are RAII compliant typedef std::vector<std::string> Strings; Void F() { Strings strings; strings.push_back(“These”); strings.push_back(“are”); strings.push_back(“a”); strings.push_back(“bunch”); strings.push_back(“of”); strings.push_back(“strings”); } //Automatic Release of the heap allocated data via stack called destructors. As you can see you don’t have to take explicit care of each variable length string nor on their holding container because their respective destructors will take care for you.
Resource usage scenarious Static inside a scope. When is know the type of data and its life expectancy. Dynamic inside a scope. When is not know the type of data but is known its life expectancy. Static outside a scope. When is know the type of data but not its life expectancy. Dynamic outside a scope. When is not know the type of data and its life expectancy. Complex multi-reference dynamic allocated resources.When is impossible to predict how a given resource will be used and where it will be referenced.
Resource usage static inside a scope typedef std::vector<std::string> Strings; Void F() {//Some dynamic strings manipulation and their automatic release Strings strings; strings.push_back(“The”); strings[0] += “se”; strings.push_back(“are”); strings.push_back(“a”); strings.push_back(“bu”); strings.back() += “nch”; strings.push_back(“of”); strings.push_back(“strings”); strings.push_back(“. Extra!”); strings.back().resize(5); strings.back().pop_back(); strings.pop_back(); } //Automatic Release of the heap allocated data via stack called destructors.
Resource usage dynamic inside a scope //An example of runtime polymorphism and automatic resource management Void SafePlayWithAnObject(const Object& v) { //create a dynamic (polymorphic) hardcopy via cloning auto_ptr<Object> p1(v.Clone()), p2; p2 = p1; //transfer the ownership of p1 to p2 and set p1 to NULL cout << p1.get() << endl << p2.get() << endl; } // automatic deallocate the dynamic object in the destructor of p2 This code will print a NULL address for the first auto_ptr object and some non-NULL address for the second, showing that the source object lost the reference during the assignment (=).
Resource usage static outside a scope typedefReal[3] Point; typedef std::vector<Point> Points; const PointsCreateRandomPolygon(Intnodes) { Pointspoints(nodes);//creates a C like array but dynamic sized for(Intn(0); n < points.size(); ++n) { points[n][0] = Random(); points[n][1] = Random(); points[n][2] = Random(); } return points; } Looking at this example, feels like C++ isn’t such a frightening language if is used with care.
Resource usage dynamic outside a scope struct Object { virtual ~Object(){}//A must have to proper enable polymorphic destruction virtual std::auto_ptr<Object> Clone() const = 0;//Abstract behavior that requires to be specialized }; struct Object1: public Object{virtual std::auto_ptr<Object> Clone() const {return new Object1(*this);}}; struct Object2: public Object{virtual std::auto_ptr<Object> Clone() const {return new Object2(*this);}}; struct Object3: public Object{virtual std::auto_ptr<Object> Clone() const {return new Object3(*this);}}; //Returns a hard copy of an object via Cloning const std::auto_ptr<Object> Factory(const Object& v) {return v.Clone();} Void Main() { const std::auto_ptr<Object> p;//is implicit initialized to NULL. Is a RAII object by default. p = Factory(Object1());//a dynamic Object1 instance is created p = Factory(Object2());//a dynamic Object2 instance is created and Object1 instance is released p = Factory(Object3());//a dynamic Object3 instance is created and Object2 instance is released }// Object3 instance is released
Complex multi-referenced dynamic allocated resources When a product allows creation of polymorphic objects that are stored in sophisticate containers and this objects are used in various places and can have cross-referenced dynamic linking at runtime smart pointers are used. VX database is a fine example of this kind of complex container with dynamic linking inside other objects.
Smart Pointers In computer science, a smart pointer is an abstract data type that simulates a pointer while providing additional features, such as automatic garbage collection or bounds checking. These additional features are intended to reduce bugs caused by the misuse of pointers while retaining efficiency. Smart pointers typically keep track of the objects that point to them for the purpose of memory management. The misuse of pointers is a major source of bugs: the constant allocation, deallocation and referencing that must be performed by a program written using pointers makes it very likely that some memory leaks will occur. Smart pointers try to prevent memory leaks by making the resource deallocation automatic: when the pointer to an object (or the last in a series of pointers) is destroyed, for example because it goes out of scope, the pointed object is destroyed too.
Garbage Collection In computer science, garbage collection (GC) is a form of automatic memory management. The garbage collector, or just collector, attempts to reclaim garbage, or memory used by objects that will never be accessed or mutated again by the application. Garbage collection is often portrayed as the opposite of manual memory management, which requires the programmer to specify which objects to deallocate and return to the memory system. However, many systems use a combination of the two approaches, and there are other techniques being studied (such as region inference) to solve the same fundamental problem. For languages that supports deterministic destruction and stack allocation C++, D, ADA GC via a specialized GC isn’t necessary because the language implements enough mechanisms to assure correct, automatic and transparent resource management as, I hope, we saw during this presentation.
Kudos goes to Wikipedia - used as reference for this presentation Dennis Ritchie - C language creator Bjarne Stroustrup - C++ language and RAII creator Alex Stepanov - STL creator Andrei Alexandrescu- Beyond C++ and STL Boost- Beyond C++ and STL
Are you interested in more? Why is programming in C++ better? What are Templates and the Standard Template Library? What are Design Patterns and how can they help us? What is Microsoft.NET and C# language?