module Graph
Tracks object traversal paths for memory analysis.
Nested
Definitions
def self.for(root, depth: nil, seen: Set.new.compare_by_identity, ignore: IGNORE, parent: nil)
Build a graph of nodes from a root object, computing usage at each level.
Signature
-
parameter
rootObject The root object to start from.
-
parameter
depthInteger Maximum depth to traverse (nil for unlimited).
-
parameter
seenSet Set of already seen objects (for internal use).
-
parameter
ignoreArray Array of types to ignore during traversal.
-
parameter
parentNode | Nil The parent node (for internal use).
-
returns
Node The root node with children populated.
Implementation
def self.for(root, depth: nil, seen: Set.new.compare_by_identity, ignore: IGNORE, parent: nil)
if depth && depth <= 0
# Compute shallow usage for this object and it's children:
usage = Usage.of(root, seen: seen, ignore: ignore)
return Node.new(root, usage, parent)
end
# Compute shallow usage for just this object:
usage = Usage.new(ObjectSpace.memsize_of(root), 1)
# Create the node:
node = Node.new(root, usage, parent)
# Mark this object as seen:
seen.add(root)
# Traverse children:
ObjectSpace.reachable_objects_from(root)&.each do |reachable_object|
# Skip ignored types:
next if ignore.any?{|type| reachable_object.is_a?(type)}
# Skip internal objects:
next if reachable_object.is_a?(ObjectSpace::InternalObjectWrapper)
# Skip already seen objects:
next if seen.include?(reachable_object)
# Recursively build child node:
node.add(self.for(reachable_object, depth: depth ? depth - 1 : nil, seen: seen, ignore: ignore, parent: node))
end
return node
end