MemorySourceMemoryGraph

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 root Object

The root object to start from.

parameter depth Integer

Maximum depth to traverse (nil for unlimited).

parameter seen Set

Set of already seen objects (for internal use).

parameter ignore Array

Array of types to ignore during traversal.

parameter parent Node | 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