IOCLASSCOUNT(8)

πŸ“¦ version 125, in nixpkgs unstable

πŸ’… IOCLASSCOUNT(8) β€” like, the whole manual, but make it make sense πŸŽ€

okay bestie, so this is ioclasscount from the System Manager's Manual, Darwin-flavored, and it is genuinely one of those tools that looks scary and then turns out to be your bestie for hunting leaks. sit down, grab a strawberry πŸ“, let's go.


✨ NAME ✨

ioclasscount β€” that's her. that's the name. iconic, no notes. πŸ‘‘


πŸ¦‹ SYNOPSIS πŸ¦‹

ioclasscount [--track] [--leaks] [--maps=PID] [--site=SITE] [--reset]
             [--start] [--stop] [--exclude] [--size=BYTES]
             [--capsize=BYTES] [--tag=tag] [--zsize=BYTES] [classname]
             [...]

like yes she has a lot of flags. she's versatile. πŸ’…


🌸 DESCRIPTION 🌸

So ioclasscount displays the instance counts of OSObject-based C++ classes in the kernel β€” and here's the lil twist that makes it spicy: each count gets incremented by the number of direct subclasses that have an instance count of at least 1.

Not me having to explain this with the classic example, but okay, the manpage does it and so will I:

Say IONetworkController is not directly instantiated, but its direct subclass IOEthernetController has any instances. Then IONetworkController's instance count will be at least 1. If another direct subclass such as IOFWController has any instances, then IONetworkController's instance count will be at least 2. and so on, forever, the math never stops, it's giving recursion energy πŸ”₯

and why, you ask? because this modification of instance counts prevents unloading of kexts defining superclasses that have no instances, but whose subclasses in other kexts have instances. lowkey genius, fr fr.

Now, the output rules, and they matter:

  • If classes are specified, instance counts are printed as a comma-separated list in the order specified. your order, your rules πŸ’–
  • If no classes are specified, instance counts for all classes are printed, one per line of output and sorted by name. alphabetically slaying ✨

This information is useful for tracking leaks. πŸ‘€ Instance counts can also be found in the root of the IORegistry in the "IOKitDiagnostics" property. so if you're the IORegistry type, she's there too 🫢


🧚 TRACKING 🧚

okay this part is the main character section, pay attention πŸ’œ

DEVELOPMENT or DEBUG kernels support collecting backtraces on IOMemoryDescriptor mapping and wiring of memory, and β€” when running with boot-arg io=0x00400000 β€” on object allocation and calls to IOMalloc*. With boot-arg io=0x02400000, capturing backtraces is enabled at startup. like, at boot. she's already working before you even showed up. 😭

The following operands are available:

  • --start β€” start capturing allocations. go go go 🏁
  • --stop β€” stop capturing allocations. okay we're done here βœ‹
  • --reset β€” reset any collected allocations. clean slate bestie 🧼
  • --track β€” display symbolicated allocation backtraces, with bytes allocated and number of calls accumulated per callsite, ordered by size. biggest first, always 🌈
  • --maps=pid β€” display symbolicated backtraces for mappings created in the process with process id pid, with bytes mapped and address, ordered by size. And if pid is -1, all processes are displayed. everyone's invited πŸ’€
  • --site=site β€” when displaying backtraces, only those containing the string site are included. For example, site could be an address in the backtrace, a symbol name, or a module name. chef's choice πŸ”
  • --leaks β€” display symbolicated allocation backtraces for potential leaks, with bytes allocated and number of calls accumulated per callsite, ordered by size. and how does it know? leaks are detected by scanning kernel virtual memory for pointer references to an allocation; allocations with no references found are a potential leak. nobody's holding onto them, so like... they're free-floating. ghosted. πŸ‘»
  • --exclude β€” if names are given, apply the command to all tracking categories excluding these names. yes, the reverse. the villain arc πŸ–€
  • --size=n β€” only report accumulated sizes >= n bytes. The default is 1 byte. tiny threshold, huge energy
  • --capsize=n β€” only capture allocations >= n bytes. The default is 1 byte. (capture β‰  report, she's picky in two different places, and honestly? respect.) πŸŽ€
  • --tag=tag β€” only report allocations with the vm tag tag.
  • --zsize=n β€” only report allocations in the kalloc zone of size n bytes.

⭐ EXAMPLES ⭐

Display instance counts for IOPCIDevice and AppleTestPCI:

/usr/sbin/ioclasscount IOPCIDevice AppleTestPCI
       IOPCIDevice = 2, AppleTestPCI = 1

look at that comma-separated order-preserved output. ate. πŸ’…

Start collecting backtraces for everything:

/usr/sbin/ioclasscount --start

Display backtraces and allocation sizes for everything:

/usr/sbin/ioclasscount --track

Display all backtraces and allocation sizes collected for OSData & OSSymbol:

/usr/sbin/ioclasscount --track OSData OSSymbol

Display all backtraces and allocation sizes collected except for OSSymbol, IOMalloc*, IOMemoryDescriptor mapping and wiring (names from IOKitDebug.h):

/usr/sbin/ioclasscount --track --exclude OSSymbol IOMalloc IOWire

the --exclude example is so satisfying, ngl 😭πŸ”₯


πŸ‘‘ SEE ALSO πŸ‘‘

ioalloccount(8), ioreg(8) β€” go read those too, bestie, they're the supporting cast and they understood the assignment 🫢


lowkey reminder: this page is from Darwin, dated November 06, 2008 β€” yes she's been serving this information since 2008 and she has not lost a step. periodt. πŸ’–βœ¨πŸŽ€πŸ¦‹πŸŒΈπŸ’…
πŸ“¦ where this page comes from
  • nixpkgs unstable: IOKitTools 125
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms