def stats(self):
        """Render garbage collection statistics page HTML content."""
        output = ['Statistics:']

        for trial in range(10):
            if request_counter.count > 0:
                break
            time.sleep(0.5)
        else:
            output.append('\nNot all requests closed properly.')

        # gc_collect isn't perfectly synchronous, because it may
        # break reference cycles that then take time to fully
        # finalize. Call it thrice and hope for the best.
        gc.collect()
        gc.collect()
        unreachable = gc.collect()
        if unreachable:
            if objgraph is not None:
                final = objgraph.by_type('Nondestructible')
                if final:
                    objgraph.show_backrefs(final, filename='finalizers.png')

            trash = {}
            for x in gc.garbage:
                trash[type(x)] = trash.get(type(x), 0) + 1
            if trash:
                output.insert(0, '\n%s unreachable objects:' % unreachable)
                trash = [(v, k) for k, v in trash.items()]
                trash.sort()
                for pair in trash:
                    output.append('    ' + repr(pair))

        # Check declared classes to verify uncollected instances.
        # These don't have to be part of a cycle; they can be
        # any objects that have unanticipated referrers that keep
        # them from being collected.
        allobjs = {}
        for cls, minobj, maxobj, msg in self.classes:
            allobjs[cls] = get_instances(cls)

        for cls, minobj, maxobj, msg in self.classes:
            objs = allobjs[cls]
            lenobj = len(objs)
            if lenobj < minobj or lenobj > maxobj:
                if minobj == maxobj:
                    output.append(
                        '\nExpected %s %r references, got %s.'
                        % (minobj, cls, lenobj),
                    )
                else:
                    output.append(
                        '\nExpected %s to %s %r references, got %s.'
                        % (minobj, maxobj, cls, lenobj),
                    )

                for obj in objs:
                    if objgraph is not None:
                        ig = [id(objs), id(inspect.currentframe())]
                        fname = 'graph_%s_%s.png' % (cls.__name__, id(obj))
                        objgraph.show_backrefs(
                            obj,
                            extra_ignore=ig,
                            max_depth=4,
                            too_many=20,
                            filename=fname,
                            extra_info=get_context,
                        )
                    output.append(
                        '\nReferrers for %s (refcount=%s):'
                        % (repr(obj), sys.getrefcount(obj)),
                    )
                    t = ReferrerTree(ignore=[objs], maxdepth=3)
                    tree = t.ascend(obj)
                    output.extend(t.format(tree))

        return '\n'.join(output)
Render garbage collection statistics page HTML content.
cherrypy/lib/gctools.py