Your loop over all objects is already great, just the !refs command needs to be replaced by something else which finds only rooted objects. My example uses Strings, because I don't have an application available using ReadLocks.
There are two possible outputs of the !refs command. A referenced object outputs e.g.
Objects referencing 02703f18 (System.String):
follow 02703a88 128 System.Globalization.NumberFormatInfo
A garbage objects looks like this:
Objects referencing 02703f30 (System.String):
NONE
You're only interested in the address of the first line in case the second line contains the word "follows". Luckily, the address is equal to ${entry}
, so we actually don't need it. Otherwise you would be in the same trouble like I am.
This brings me to this question about .if.
You can use .foreach again on the output of !refs. Let's have a look at this on a single object first:
.foreach (reftoken {!refs 027045cc -target}) { .printf "${reftoken}\n" }
This prints one word per line and we are interested only in the fifth, which means we can initially skip 4 items and then skip the rest, which gives us
.foreach /pS 4 /ps 3 (reftoken {!refs 027045cc -target}) { .printf "${reftoken}\n" }
For robustness purposes, let's use /ps 99
.
Next we need to check if this token equals follow, which is done by
.if ($sicmp("${reftoken}","follow") == 0) { .echo found follow }
And combine it all together:
.foreach (entry {!dumpheap -type System.String -short})
{
.foreach /pS 4 /ps 99 (reftoken {!refs ${entry} -target})
{
.if ($sicmp("${reftoken}","follow") == 0)
{
.printf "${entry}\n"
}
}
}
In one line:
.foreach (entry {!dumpheap -type System.String -short}){.foreach /pS 4 /ps 99 (reftoken {!refs ${entry} -target}) {.if ($sicmp("${reftoken}","follow") == 0) {.printf "${entry}\n"}}}
Of course you can replace .print by any other command which is helpful in your situation.
I hope you can adapt this sample to use ReadLock.