Memory::LeakSourceMemoryLeakCluster

class Cluster

Detects memory leaks in a cluster of processes.

This class is used to manage a cluster of processes and detect memory leaks in each process. It can also enforce cluster-wide memory limits in two ways:

  1. Total Size Limit (total_size_limit): Limits the total memory used by all processes in the cluster, calculated as max(shared memory) + sum(private memory).

  2. Free Size Minimum (free_size_minimum): Ensures the host system maintains a minimum amount of free memory by terminating processes when free memory drops too low.

Both limits can be active simultaneously. Processes are terminated in order of largest private memory first to maximize the impact of each termination.

Definitions

def initialize(total_size_limit: nil, free_size_minimum: nil)

Create a new cluster.

Signature

parameter total_size_limit Numeric | Nil

The total memory limit for the cluster.

parameter free_size_minimum Numeric | Nil

The minimum free memory required on the host, in bytes.

Implementation

def initialize(total_size_limit: nil, free_size_minimum: nil)
	@total_size = nil
	@total_size_limit = total_size_limit
	@free_size_minimum = free_size_minimum
	
	@processes = {}
end

def as_json(...)

Signature

returns Hash

A serializable representation of the cluster.

Implementation

def as_json(...)
	{
		total_size: @total_size,
		total_size_limit: @total_size_limit,
		free_size_minimum: @free_size_minimum,
		processes: @processes.transform_values(&:as_json),
	}
end

def to_json(...)

Signature

returns String

The JSON representation of the cluster.

Implementation

def to_json(...)
	as_json.to_json(...)
end

attr :total_size

Signature

attribute Numeric | Nil

The total size of the cluster.

attr_accessor :total_size_limit

Signature

attribute Numeric | Nil

The total size limit for the cluster, in bytes, if which is exceeded, the cluster will terminate processes.

attr_accessor :free_size_minimum

Signature

attribute Numeric | Nil

The minimum free memory required on the host, in bytes. If free memory falls below this minimum, the cluster will terminate processes.

attr :processes

Signature

attribute Hash(Integer, Monitor)

The process IDs and monitors in the cluster.

def add(process_id, **options)

Add a new process ID to the cluster.

Implementation

def add(process_id, **options)
	@processes[process_id] = Monitor.new(process_id, **options)
end

def remove(process_id)

Remove a process ID from the cluster.

Implementation

def remove(process_id)
	@processes.delete(process_id)
end

def sample!

Sample the memory usage of all processes in the cluster.

Implementation

def sample!
	@processes.each_value(&:sample!)
end

def check!(&block)

Check all processes in the cluster for memory leaks.

Signature

yields {|process_id, monitor| ...}

each process ID and monitor that is leaking or exceeds the memory limit.

Implementation

def check!(&block)
	self.sample!
	
	leaking = []
	
	@processes.each do |process_id, monitor|
		if monitor.leaking?
			Console.debug(self, "Memory Leak Detected!", process_id: process_id, monitor: monitor)
			
			leaking << [process_id, monitor]
		end
	end
	
	if block_given?
		leaking.each(&block)
		
		# Finally, enforce any per-cluster memory limits:
		if @total_size_limit
			enforce_total_size_limit!(@total_size_limit, &block)
		end
		
		# Enforce minimum free memory requirement:
		if @free_size_minimum
			enforce_free_size_minimum!(@free_size_minimum, &block)
		end
	end
	
	return leaking
end