or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

graph-visualization.mdgrowth-analysis.mdindex.mdobject-discovery.mdobject-statistics.mdreference-chains.md

object-discovery.mddocs/

0

# Object Discovery and Access

1

2

Functions for finding specific objects by type or memory address, and identifying objects that may indicate memory management issues. These tools help locate objects for further analysis and investigation.

3

4

## Capabilities

5

6

### Type-Based Object Discovery

7

8

Find all objects of a specific type tracked by the garbage collector.

9

10

```python { .api }

11

def by_type(typename, objects=None):

12

"""

13

Return objects tracked by the garbage collector with a given class name.

14

15

Args:

16

typename (str): Class name, can be short ('MyClass') or fully qualified ('mymodule.MyClass')

17

objects (list, optional): Custom object collection to search instead of gc.get_objects()

18

19

Returns:

20

list: List of objects matching the type name

21

22

Note:

23

The garbage collector does not track simple objects like int or str.

24

"""

25

```

26

27

Usage examples:

28

29

```python

30

import objgraph

31

32

# Find all list objects

33

all_lists = objgraph.by_type('list')

34

print(f"Found {len(all_lists)} list objects")

35

36

# Find custom class instances

37

my_objects = objgraph.by_type('MyClass')

38

for obj in my_objects:

39

print(f"MyClass instance: {obj}")

40

41

# Use fully qualified names to be specific

42

specific_objects = objgraph.by_type('mymodule.MyClass')

43

44

# Search within a specific collection

45

leaking_objects = objgraph.get_leaking_objects()

46

leaking_dicts = objgraph.by_type('dict', leaking_objects)

47

48

# Combine with other analysis

49

large_lists = [lst for lst in objgraph.by_type('list') if len(lst) > 1000]

50

print(f"Found {len(large_lists)} large lists")

51

```

52

53

### Address-Based Object Access

54

55

Retrieve objects using their memory addresses, useful for tracking specific object instances.

56

57

```python { .api }

58

def at(addr):

59

"""

60

Return an object at a given memory address.

61

62

Args:

63

addr (int): Memory address from id(obj)

64

65

Returns:

66

object or None: Object at the address, or None if not found

67

68

Note:

69

Only works on objects tracked by the garbage collector.

70

The reverse of id(obj): at(id(obj)) is obj should be True.

71

"""

72

```

73

74

Usage examples:

75

76

```python

77

import objgraph

78

79

# Basic address lookup

80

my_list = [1, 2, 3]

81

address = id(my_list)

82

found_obj = objgraph.at(address)

83

print(f"Found same object: {found_obj is my_list}")

84

85

# Use with object tracking

86

objects_to_track = []

87

for i in range(10):

88

new_dict = {'index': i}

89

objects_to_track.append(id(new_dict))

90

91

# Later retrieve the objects

92

for addr in objects_to_track:

93

obj = objgraph.at(addr)

94

if obj is not None:

95

print(f"Object at {addr}: {obj}")

96

else:

97

print(f"Object at {addr} was garbage collected")

98

```

99

100

### Bulk Address Resolution

101

102

Retrieve multiple objects from a set of memory addresses efficiently.

103

104

```python { .api }

105

def at_addrs(address_set):

106

"""

107

Return a list of objects for a given set of memory addresses.

108

109

Args:

110

address_set (set): Set of memory addresses from id() calls

111

112

Returns:

113

list: List of objects found at those addresses, in arbitrary order

114

115

Note:

116

Objects are returned in arbitrary order.

117

Only works on objects tracked by the garbage collector.

118

"""

119

```

120

121

Usage examples:

122

123

```python

124

import objgraph

125

126

# Use with get_new_ids for object tracking

127

objgraph.get_new_ids(limit=0) # Establish baseline

128

129

# Create some objects

130

a = [1, 2, 3]

131

b = [4, 5, 6]

132

c = {'key': 'value'}

133

134

# Get IDs of newly created objects

135

new_ids = objgraph.get_new_ids(limit=0)

136

137

# Retrieve the actual list objects

138

new_lists = objgraph.at_addrs(new_ids.get('list', set()))

139

print(f"Created {len(new_lists)} new lists")

140

print(f"Our list 'a' is in new lists: {a in new_lists}")

141

print(f"Our list 'b' is in new lists: {b in new_lists}")

142

143

# Combine with filtering

144

large_new_lists = [lst for lst in new_lists if len(lst) > 5]

145

146

# Save addresses for later analysis

147

important_object_ids = {id(obj) for obj in some_important_objects}

148

# ... later ...

149

still_alive = objgraph.at_addrs(important_object_ids)

150

print(f"{len(still_alive)} of {len(important_object_ids)} objects still exist")

151

```

152

153

### Leak Detection

154

155

Identify objects that have no referrers, which may indicate reference-counting bugs or orphaned objects.

156

157

```python { .api }

158

def get_leaking_objects(objects=None):

159

"""

160

Return objects that do not have any referrers.

161

162

Args:

163

objects (list, optional): Custom object collection to analyze instead of gc.get_objects()

164

165

Returns:

166

list: List of objects without referrers

167

168

Note:

169

These could indicate reference-counting bugs in C code or be legitimate.

170

The garbage collector does not track simple objects like int or str.

171

Calls gc.collect() automatically.

172

"""

173

```

174

175

Usage examples:

176

177

```python

178

import objgraph

179

180

# Find potentially leaking objects

181

leaking = objgraph.get_leaking_objects()

182

print(f"Found {len(leaking)} objects without referrers")

183

184

# Analyze leaking objects by type

185

if leaking:

186

leak_stats = objgraph.typestats(leaking)

187

print("Leaking object types:")

188

for obj_type, count in sorted(leak_stats.items(), key=lambda x: x[1], reverse=True):

189

print(f" {obj_type}: {count}")

190

191

# Investigate specific leaking objects

192

if leaking:

193

for obj in leaking[:5]: # Look at first 5

194

print(f"Leaking {type(obj).__name__}: {repr(obj)[:100]}")

195

196

# Try to find what might be keeping references

197

# (though by definition, these objects have no referrers)

198

objgraph.show_backrefs([obj], max_depth=2)

199

200

# Filter leaking objects

201

large_leaking = [obj for obj in leaking

202

if hasattr(obj, '__len__') and len(obj) > 100]

203

204

# Combine with custom object collection

205

my_objects = objgraph.by_type('MyClass')

206

leaking_my_objects = objgraph.get_leaking_objects(my_objects)

207

if leaking_my_objects:

208

print(f"Found {len(leaking_my_objects)} leaking MyClass instances")

209

```

210

211

## Common Workflows

212

213

### Object Lifecycle Tracking

214

215

```python

216

import objgraph

217

import weakref

218

219

class TrackedObject:

220

def __init__(self, name):

221

self.name = name

222

223

def __repr__(self):

224

return f"TrackedObject({self.name})"

225

226

# Create some objects to track

227

objects = [TrackedObject(f"obj_{i}") for i in range(5)]

228

object_ids = {id(obj) for obj in objects}

229

230

print(f"Created {len(objects)} objects")

231

232

# Clear some references

233

del objects[2:4] # Remove references to obj_2 and obj_3

234

235

# Check which objects still exist

236

surviving_objects = objgraph.at_addrs(object_ids)

237

print(f"{len(surviving_objects)} objects survived")

238

239

# Force garbage collection and check again

240

import gc

241

gc.collect()

242

surviving_after_gc = objgraph.at_addrs(object_ids)

243

print(f"{len(surviving_after_gc)} objects survived after GC")

244

```

245

246

### Memory Leak Investigation

247

248

```python

249

import objgraph

250

251

# Identify potential problem objects

252

leaking = objgraph.get_leaking_objects()

253

if leaking:

254

# Group by type

255

leak_by_type = {}

256

for obj in leaking:

257

obj_type = type(obj).__name__

258

leak_by_type.setdefault(obj_type, []).append(obj)

259

260

# Focus on most numerous type

261

most_common_type = max(leak_by_type.keys(), key=lambda t: len(leak_by_type[t]))

262

problem_objects = leak_by_type[most_common_type]

263

264

print(f"Most leaking type: {most_common_type} ({len(problem_objects)} instances)")

265

266

# Analyze a few examples

267

for obj in problem_objects[:3]:

268

print(f"Investigating: {repr(obj)[:100]}")

269

# Even though these have no referrers, show the object's contents

270

objgraph.show_refs([obj], max_depth=2)

271

```