class Usage
Tracks memory usage statistics including size and object count.
Can be used to measure allocations or compute usage of object graphs.
Definitions
def initialize(size = 0, count = 0)
Initialize a new usage tracker.
Signature
-
parameter
sizeInteger The total size in bytes.
-
parameter
countInteger The total count of objects.
Implementation
def initialize(size = 0, count = 0)
@size = size
@count = count
end
attr_accessor :size
attr_accessor :count
def [](key)
Access usage attributes by key.
Signature
-
parameter
keySymbol The attribute name (:size, :count, :memory, :memsize).
Implementation
def [](key)
public_send(key)
end
def <<(allocation)
Add an allocation to this usage.
Signature
-
parameter
allocationAllocation The allocation to add.
Implementation
def << allocation
self.size += allocation.memsize
self.count += 1
return self
end
def add!(other)
Add another usage to this usage.
Signature
-
parameter
otherUsage The usage to add.
Implementation
def add!(other)
self.size += other.size
self.count += other.count
return self
end
def self.of(root, seen: Set.new.compare_by_identity, ignore: IGNORE)
Compute the usage of an object and all reachable objects from it.
The root is always visited even if it is in seen.
Signature
-
parameter
rootObject The root object to start traversal from.
-
parameter
seenHash(Object, Integer) The seen objects (should be compare_by_identity).
-
returns
Usage The usage of the object and all reachable objects from it.
Implementation
def self.of(root, seen: Set.new.compare_by_identity, ignore: IGNORE)
count = 0
size = 0
queue = [root]
while object = queue.shift
# Add the object to the seen set:
seen.add(object)
# Update the count and size:
count += 1
size += ObjectSpace.memsize_of(object)
# Add the object's reachable objects to the queue:
ObjectSpace.reachable_objects_from(object)&.each do |reachable_object|
# Skip ignored types:
next if ignore.any?{|type| reachable_object.is_a?(type)}
# Skip internal objects - they don't behave correctly when added to `seen` and create unbounded recursion:
next if reachable_object.is_a?(ObjectSpace::InternalObjectWrapper)
# Skip objects we have already seen:
next if seen.include?(reachable_object)
queue << reachable_object
end
end
return new(size, count)
end
def as_json(...)
Convert this usage to a JSON-compatible hash.
Signature
-
parameter
optionsHash | Nil Optional JSON serialization options.
-
returns
Hash Hash with
:sizeand:countkeys.
Implementation
def as_json(...)
{
size: @size,
count: @count
}
end
def to_json(...)
Convert this usage to a JSON string.
Signature
-
returns
String JSON representation of this usage.
Implementation
def to_json(...)
as_json.to_json(...)
end
def to_s
Generate a human-readable string representation.
Signature
-
returns
String Formatted string showing size and allocation count.
Implementation
def to_s
"(#{Memory.formatted_bytes(@size)} in #{@count} allocations)"
end