Remove a class instance in Ruby? - ruby

I've read the notes on GC happening at an undetermined time after disconnecting any references by instance variables, but would the second line in the delete method be foolish, unnecessary or thorough?
class MyClass
# new instances added to ##instances
...
def delete
##instances.delete(self)
self.instance_variables.each{|v| self.instance_variable_set(v,nil)}
end
end

Unnecessary. If you really want to trigger GC, use GC.start or ObjectSpace.garbage_collect.
And because it can't be recommended often enough, once again:
http://viewsourcecode.org/why/hacking/theFullyUpturnedBin.html

The method delete executes in the scope of the instance that is being removed from the ##instances structure, hence it cannot be garbage collected. Something triggered that method to run, and that something is currently holding a reference to it, therefore it cannot be garbage collected until after the method has returned (and the reference to the object been cleared).
That being said, the second line is completely unnecessary. Even if one of the instance variables pointed back to the object itself the GC is clever enough to figure that out (or rather, it just ignores it since it's not a reference counting collector).
Don't try to manually manage memory, it will not pay off. Whether or not you clear the references to the objects in those instance variables the GC decides when they will be freed. If I interpret the idea of your code example correctly all references to the host object are cleared after delete has run, and in that case it doesn't matter if its instance variables are cleared too, the objects will be just as eligible for garbage collection either way. Objects are GC'ed when they are no longer reachable, it does not matter if other unreachable objects have references to them.

Related

How to destroy Ruby object?

Suppose there is simple object like:
object = Object.new
As I know this creates Object in memory (RAM).
Is there a way to delete this object from RAM?
Other than hacking the underlying C code, no. Garbage collection is managed by the runtime so you don't have to worry about it. Here is a decent reference on the algorithm in Ruby 2.0.
Once you have no more references to the object in memory, the garbage collector will go to work. You should be fine.
The simple answer is, let the GC (garbage collector) do its job.
When you are ready to get rid of that reference, just do object = nil. And don't make reference to the object.
The garbage collector will eventually collect that and clear the reference.
(from ruby site)
=== Implementation from GC
------------------------------------------------------------------------------
GC.start -> nil
GC.start(full_mark: true, immediate_sweep: true) -> nil
------------------------------------------------------------------------------
Initiates garbage collection, unless manually disabled.
This method is defined with keyword arguments that default to true:
def GC.start(full_mark: true, immediate_sweep: true); end
Use full_mark: false to perform a minor GC. Use immediate_sweep: false to
defer sweeping (use lazy sweep).
Note: These keyword arguments are implementation and version dependent. They
are not guaranteed to be future-compatible, and may be ignored if the
underlying implementation does not support them.
Ruby Manages Garbage Collection Automatically
For the most part, Ruby handles garbage collection automatically. There are some edge cases, of course, but in the general case you should never have to worry about garbage collection in a typical Ruby application.
Implementation details of garbage collection vary between versions of Ruby, but it exposes very few knobs to twiddle and for most purposes you don't need them. If you find yourself under memory pressure, you may want to re-evaluate your design decisions rather than trying to manage the symptom of excess memory consumption.
Manually Trigger Garbage Collection
In general terms, Ruby marks objects for garbage collection when they go out of scope or are no longer referenced. However, some objects such as Symbols never get collected, and persist for the entire run-time of your program.
You can manually trigger garbage collection with GC#start, but can't really free blocks of memory the way you can with C programs from within Ruby. If you find yourself needing to do this, you may want to solve the underlying X/Y problem rather than trying to manage memory directly.
You can't explicitly destroy object. Ruby has automatic memory management. Objects no longer referenced from anywhere are automatically collected by the garbage collector built in the interpreter.
Good article to read on how to do allocation wisely, and a few tools you can use to fine tune.
http://merbist.com/2010/07/29/object-allocation-why-you-should-care/

Check Value of .NET Handle ^

Here's my situation:
I have .NET wrapper-objects in a C++/CLI layer that hold pointers to unmanaged C++ objects. I've implemented the finalizer so that it deletes the unmanaged memory pointed to by the wrapper-object on garbage-collection and sets the pointer to null.
Here's the problem:
I'm watching the finalizer for the .NET wrapper-object and it gets called twice and tries to delete the same memory twice, indicating that I have somehow created 2 .NET wrapper objects that go out-of-scope, and are garbage collected while I'm still expecting the wrapper object to be in scope (these wrapper objects are getting passed to a VB.NET application).
Here's my question:
Is there anyway for me to check the handle value so that I can confirm where the wrapper objects are getting created (copied or whatever)? Currently I'm looking at the handle values (EG - 0x0014fe80), but I see 3 different values for when the object is created, added to a collection, and deleted. So I'm not sure if the GC is just moving stuff around and this is the same object, or if I'm actually seeing 3 different objects that reference the same unmanaged memory. I would like to resolve the duplicate object copies if possible, but I understand that I will probably want to implement some sort of smart pointer so that this doesn't happen.
Thanks,
Ian
Take a look at this question
Here is an implementation of a scoped_ptr that is noncopyable and has an auto-release mechanism for unmanaged objects, by #Ben Voigt
Yeah, I ended up modifying an auto_ptr class to be a shared pointer to ensure that the unmanaged memory is only deleted once through the smart pointer finalizer. I'm assuming I did something similar to all the other implementations; I created a static dictionary in the auto_ptr template class, using the native pointer value as the key, that is checked every time the finalizer is called to update the count of each item, or delete the memory.

Difference between local and instance variables in ruby

I am working on a script that creates several fairly complex nested hash datastructures and then iterates through them conditionally creating database records. This is a standalone script using active record. After several minutes of running I noticed a significant lag in server responsiveness and discovered that the script, while being set to be nice +19, was enjoying a steady %85 - %90 total server memory.
In this case I am using instance variables simply for readability. It helps knowing what is going to be re-used outside of the loop vs. what won't. Is there a reason to not use instance variables when they are not needed? Are there differences in memory allocation and management between local and instance variables? Would it help setting #variable = nil when its no longer needed?
An instance variable continues to exist for the life of the object that holds it. A local variable exists only within a single method, block or module body.
If you're assuming objects in your object's instance variables will be garbage-collected just because you don't intend to refer to them in the future, that isn't how it works. The garbage collector only knows whether there's a reachable reference to the object — and there is if it's in an instance variable.
Setting #variable = nil destroys the reference to the object that the instance variable once pointed to. When there are no more remaining references to an object, it should be collected by the garbage collector eventually. I say "eventually" because the GC is somewhat unpredictable. However, it's easy to have a memory leak by a "dangling reference" and possibly (depending on how the GC is implemented) circular references. What else refers to this object?

Some questions on how code may influence the GC process

1) Does adding a Dispose(), or finalize method, have any impact on making an object be GC'd soon? I ask this as my manager wrote some code, adding a finalize() method, in the hope it would be GC'd.
But I argued that the object has to be "marked" for collection first, if it meets certain criteria.
2) Does writing "o = null" (where o is a ref type) have any impact on making an object be GC'd sooner? Either in C++ or Java/C#.
Thanks
Note, this answer is regarding .NET. I don't know how Java does this, at all.
Let's start with the addition of a finalizer, or rather, what happens when an object without one is collected.
When GC runs, and discovers objects for which there are no rooted references, they're collected.
However, if you add a finalizer to the class, when GC discovers that the object is eligible for collection, it is placed on a list, because it has a finalizer.
This list is processed besides the normal GC, and since the object now has a rooted reference (that list), it is temporarily not eligible for collection. The list is processed by iterating over it and calling all the finalizers. There's lots of details here that I'm glossing over.
Once the finalizer for an object has been called, the object is removed from the list. Sometimes later, when GC again discovers that object, though it still has the finalizer method in its type, the object has been marked so that the finalizer no longer needs to run, and the object is now collected as though it didn't have a finalizer to begin with.
So, actually, adding a finalizer will not make the object be collected sooner, rather it will actually make the object be collected later.
The only way to make an object eligible for collection is to remove all rooted references to it.
Calling Dispose also has no meaning in this regard. Dispose is just a method call, and calling it does in no way mark the object as eligible for collection. If, after calling Dispose, you still have rooted references to the object, it will be left in memory and not collected.
However, if your class has a Dispose method, and a finalizer, the Dispose method typically unregisters the object from finalization. Basically you say "Dispose has now taken care of everything that the finalizer would do, so there's no longer any point in calling the finalizer". If it does this, calling the Dispose method, and then removing all live references to the object, will make it both eligible for collection, and skip the finalization step.
On to your second question.
As I said above, you need to remove all rooted references to the object. A rooted reference is a reference that can be tracked back to something that lives for the duration of the program, be it static fields, local variables on still live call stacks, etc. Once all those are gone, the object is eligible for collection.
But the GC in .NET is really aggressive. The JITter will store information alongside the code telling GC which portions of a method that uses the local variables, and if a variable is no longer used, for instance for the last portion of a method, even though the variable still references an object, that variable is considered to be unnecessary, and thus the object can be collected.
For instance, here:
public void Test()
{
object o = new object();
// do something else
}
In this case, as long as the o variable is no longer used in the method, during that "do something else" code, the object in it can be collected.
The JITter will detect when the program is running in the debugger, and then artificially extend the lifetime of all variables to the end of their scopes, so that you can inspect variables even though they technically aren't considered "live" any more. But when not running in the debugger, that o above isn't explicitly nulled doesn't mean anything, the object can still be collected.
Now, if o was a static field, which lives for much longer than a method call, then yes, explicitly setting it to null will of course help, because now you're removing rooted references to the object.
Also, if the variable is re-used later in the method, you can help make the current object eligible for collection by setting it to null. (note I'm not entirely sure about this, perhaps the JITter can see that the current value is not needed, so it can be collected because later on you overwrite the contents anyway)
So to summarize:
Don't add a finalizer unless you need it
Calling Dispose has no bearing on how soon the object becomes eligible for collection
To "mark" an object as eligible for collection, get rid of all rooted references to it
You can help with collection by explicitly setting variables and fields to null, but for local variables no longer in used by a method, it may not be necessary (but won't hurt)
Java:
1) no, finalize() is called when the garbage collector determines that the object is GC-able - it has no bearing on when GC happens, or whether the object will be GC-ed on a given run. In fact, implementing finalize() delays an object from being GCed - the first GC pass determines that the object is GC-able (i.e. finalize() should be called) and it isn't until the second pass that the object is freed - assuming that the finalizer didn't create a new reference to the object!
2) holding onto references will delay GC, so breaking a reference can allow an object to be GCed earlier if the object holding the reference is still reachable. It's no guarantee that the object will be GCed earlier, though.

When a variable goes out of scope does that mean it doesn't exist?

I'm not sure I understand scope - does an out-of-scope variable (I'm using Ruby) exist in memory somewhere or does it stop existing (I know you can't access it). Would it be inaccurate to say that an out-of-scope variable does not exist any more?
Maybe this is a philosophical question.
If you are using managed language then you don't allocate and unallocate memory so as far as you are concerned it no longer exists.
Technically it does but GCs tend not to be deterministic so technically it's hard to say when it actually vanishes.
A variable is not the same as the value it holds.
The variable itself ceases to exist when it goes out of scope. The value that the variable held may represent an object, and that object may continue to exist beyond the lifetime of the variable. The garbage collector reclaims the object later.
When it goes out of scope it still exists (in the sense that it has some memory allocated to it) for some time, until garbage collection cleans it up. But as you imply, it's lost it's name and is unreachable.
When a variable falls out of scope is anyone around to hear it scream?
This isn't a ruby question so much as a general question about garbage collection. In a garbage collected language such as Ruby or C# when a variable falls out of scope it's marked in some manner that says it's no longer in use. When this happens you can't get at it any more and it sits around twiddling its thumbs - but it does still have memory allocated to it.
At some point the garbage collector will wake up and look for variables marked as not in use. It will dispose of them and at that point they're no longer in memory at all.
It can be more complicated than this, depending on how the garbage collector works, but it's close enough :)
It exists for a little bit until the garbage collector disposes it (if it can).
Rob Kennedy has this answered appropriately, but I thought I would add a little more detail.
The important thing to recognize is the difference between a variable and the value it represents.
Here's an example (in C# because I don't know Ruby):
object c = null;
if (1 == 1) // Just to get a different scope
{
var newObj = new SomeClass();
newObj.SomeProperty = true;
c = newObj;
}
In the code above, newObj goes out of scope at the end of the if statement and as such "doesn't exist", but the value that it was referring to is still alive and well, referenced by c. Once all of the references to the object are gone, then the garbage collector will take care of cleaning it up.
If you're talking about file objects, it becomes more than a philosophical question. If I recall correctly, files do not close automatically when they go out of scope - they only close if you ask them to close, or if you use a File.open do |file| style block, or if they get garbage collected. This can be an issue if other code (or unit tests) try to read the contents of that file and it hasn't yet been flushed.

Resources