Class: Contrast::Agent::Assess::Finalizers::Hash
- Defined in:
- lib/contrast/agent/assess/finalizers/hash.rb
Overview
An extension of Hash that doesn’t impact GC of the object being stored by storing its ID as a Key to lookup and registering a finalizer on the object to remove its entry from the Hash immediately after it’s GC’d.
Constant Summary collapse
- FROZEN_FINALIZED_IDS =
Set.new
Instance Method Summary collapse
- #[](key) ⇒ Object
- #[]=(key, obj) ⇒ Object
-
#finalize(key_id) ⇒ Object
Remove the given key from our frozen and properties tracking during finalization of the Object to which the given key_id pertains.
-
#pre_freeze(key) ⇒ Object
Frozen things cannot be finalized.
-
#trackable?(key) ⇒ Boolean
Something is trackable if it is not a collection and either not frozen or it was frozen after we put a finalizer on it.
-
#tracked?(key) ⇒ Boolean
Determine if the given Object is tracked, meaning it has a known set of properties and those properties are tracked.
Instance Method Details
#[](key) ⇒ Object
28 29 30 |
# File 'lib/contrast/agent/assess/finalizers/hash.rb', line 28 def [] key super key.__id__ end |
#[]=(key, obj) ⇒ Object
17 18 19 20 21 22 23 24 25 26 |
# File 'lib/contrast/agent/assess/finalizers/hash.rb', line 17 def []= key, obj # We can't finalize frozen things, so only act on those that went # through .pre_freeze if key.cs__frozen? return unless FROZEN_FINALIZED_IDS.include?(key.__id__) else ObjectSpace.define_finalizer(key, finalize(key.__id__)) end super key.__id__, obj end |
#finalize(key_id) ⇒ Object
Remove the given key from our frozen and properties tracking during finalization of the Object to which the given key_id pertains. NOTE: by necessity, this is the only method which takes the __id__, not the Object itself. You CANNOT pass the Object to this as a finalizer cannot hold reference to the Object being finalized; that prevents GC, which introduces a memory leak and defeats the entire purpose of this.
69 70 71 72 73 74 |
# File 'lib/contrast/agent/assess/finalizers/hash.rb', line 69 def finalize key_id proc do FROZEN_FINALIZED_IDS.delete(key_id) delete(key_id) end end |
#pre_freeze(key) ⇒ Object
Frozen things cannot be finalized. To avoid any issue here, we intercept the #freeze call and set finalizers on the Object. To ensure later we know it’s been pre-finalized, we add it’s __id__ to our tracking.
83 84 85 86 87 88 89 90 91 92 |
# File 'lib/contrast/agent/assess/finalizers/hash.rb', line 83 def pre_freeze key return if key.cs__frozen? return if FROZEN_FINALIZED_IDS.include?(key.__id__) ObjectSpace.define_finalizer(key, finalize(key.__id__)) FROZEN_FINALIZED_IDS << key.__id__ rescue StandardError => _e nil end |
#trackable?(key) ⇒ Boolean
Something is trackable if it is not a collection and either not frozen or it was frozen after we put a finalizer on it.
37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/contrast/agent/assess/finalizers/hash.rb', line 37 def trackable? key # Track things in these, not them themselves. return false if Contrast::Utils::DuckUtils.iterable_hash?(key) return false if Contrast::Utils::DuckUtils.iterable_enumerable?(key) # If it's not frozen, we can finalize/ track it. return true unless key.cs__frozen? # Otherwise, we can only track it if we've finalized it in our # freeze patch. FROZEN_FINALIZED_IDS.include?(key.__id__) end |
#tracked?(key) ⇒ Boolean
Determine if the given Object is tracked, meaning it has a known set of properties and those properties are tracked.
55 56 57 |
# File 'lib/contrast/agent/assess/finalizers/hash.rb', line 55 def tracked? key key?(key.__id__) && fetch(key.__id__, nil)&.tracked? end |