简体   繁体   中英

Ruby - Clear all the global variables

I am using an existing framework for parallel execution. There are so many global variables being used in this. I could see some of the global variables (yes, we should avoid it, but in this case, I don't have an option) are creating issues. global_variables shows the list of all the global variables used. I want to clear them at the end of every execution. Any suggestions, please? ((

TL;DR

You don't want to clear all globals, as Ruby depends on a number of global variables and constants for proper operation. It's okay to clear the ones you've defined, though.

However, you can't actually undefine globals, although you can certainly re-assign their values. Refactoring to namespaced or lexically-scoped variables should be a longer term objective, even if the suggestions below work for you now. There are many options for passing bindings, values, configuration settings, and object references that don't rely on globals, and reducing variable scope is usually the right thing to do in most cases.

That said, here are some suggestions that may help with your situation. I've also noted some edge cases that may or may not apply to your code, but that should be in the back of your mind when dealing with top-level bindings and global namespaces.

You Can't Undefine or Garbage-Collect Globals

By definition, global variables never go out of scope. That also means the variables themselves can never be garbage-collected either.

Additionally, similarly to instance variables but unlike class or local variables, global variables are auto-vivified * as nil when referenced to prevent NameError. Even if you never actually define $foo , $foo == nil #=> true .


* As a subtle distinction, defined? $foo #=> nil defined? $foo #=> nil while $foo = nil; defined? $foo #=> "global-variable" $foo = nil; defined? $foo #=> "global-variable" $foo = nil; defined? $foo #=> "global-variable" , but I don't think that has any practical bearing on your question.


If your primary goal is just to "unset" the values of your globals, you can do something like:

NILABLE_GLOBALS = %w[$foo $bar $baz]
NILABLE_GLOBALS.map { eval "#{_1} = nil" }

While the variables are all still technically defined, pragmatically they will respond similarly to being undefined, eg by being equal to nil .

Reducing Memory Consumed by Globals

This approach may also minimize the memory footprint of the globals by pointing them all to what amounts to a singleton object, eg the sole instance of NilClass. This should reduce memory usage if the values previously stored in your globals are garbage collected when nothing references them any longer. There are perhaps several edge cases, like frozen strings stored in the TOPLEVEL_BINDING, where I'm unsure if the values will truly lose all references and thus be garbage collected, but that's more of a memory management issue than a value assignment or object identity issue, and if memory were a primary concern you wouldn't be using globals in the first place.

So long as you aren't relying on defined? returning nil when the values are reset, this seems like your best option short of refactoring your code to use variables that can go out of scope.

Additional Caveats

If you're using a much older version of Ruby that can't garbage-collect Symbols, assign String objects to your globals when you can. You might also disable frozen strings as a default if you find that they aren't being garbage collected even when no longer referenced. You can inspect ObjectSpace after calling the GC module to look for unwanted Symbol and String objects if memory bloats excessively. While these are unlikely to be real problems for you, at least you have a starting point if they are.

At some early point in your program, record the global variables that are provided by the Ruby interpreter itself and store that it in a constant:

OrigGlobalVars = global_variables

I don't think there is a way to undefine global variables, but you can set all the new ones created by your code to nil by doing this:

(global_variables - OrigGlobalVars).each { |g| eval "#{g} = nil" }

This certainly might break some code that uses the global variables, because the code might not be designed to gracefully handle the case where the variable is nil. But you can fix those cases as they come up.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM