Bug 163151 - Web Inspector: Heap Snapshot should be able to tell me if an object was collected
Summary: Web Inspector: Heap Snapshot should be able to tell me if an object was colle...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Web Inspector (show other bugs)
Version: WebKit Local Build
Hardware: All All
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2016-10-07 15:58 PDT by Saam Barati
Modified: 2016-12-13 15:35 PST (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Saam Barati 2016-10-07 15:58:08 PDT
Currently, I'm trying to track the lifetime of a particular object. I want to find out if it was collected between GCs. I have no way of finding this information out now. It'd be very nice to be able to ask some questions about a particular object:
1. Did it ever get deleted?
2. Between which two snapshots was it deleted?

Also, it could be neat to switch to a view where deletions are part of heap snapshot diffs. This would help me out a lot.

Currently, it's very hard to tell if an object is still alive because it's impossible to track all the paths to an object, so it's hard to tell if it might exist thought a particular path in the object graph that I'm not aware of. The reason it's hard to track all paths is that global objects point to many things.
Comment 1 Radar WebKit Bug Importer 2016-10-07 15:58:22 PDT
<rdar://problem/28679064>
Comment 2 Joseph Pecoraro 2016-10-11 13:05:22 PDT
When new snapshots are taken, we automatically remove GC'd objects from earlier snapshots. Since our main focus was on detecting leaked objects, the current UI is optimized for viewing objects that are still alive at the end of a recording (since that implicitly takes a snapshot).

We know the list of collected objects when we remove them from older snapshots. We could have a way of showing just the deleted objects. Likewise we could have a way to show all objects, alive and dead.
Comment 3 Geoffrey Garen 2016-10-11 13:33:50 PDT
One nice thing about the "alive + dead" display is that it allows you to see memory usage go up and / or down between snapshots.

Today, since old snapshots update when new snapshots are taken, they retroactively edit their total memory usage numbers, erasing debugging history.
Comment 4 Timothy Hatcher 2016-10-11 14:01:01 PDT
Showing the dead objects in the tree was very distracting though, since we couldn't preview what they were. On even a small page, there could be hundreds of objects cluttering the object graphs.

Would it help to have a live and dead memory total, but only have the tree show the live objects?
Comment 5 Saam Barati 2016-10-11 14:22:54 PDT
My perfect debugging scenario for what I was trying to do would go like this:
1. Take a snapshot
2. Pause JS execution
3. Find an object inside the snapshot
4. Ask the inspector to notify me when it gets destructed
5. continue JS execution

alternatively, some API for doing this like:
```
let object = new Array(someLargeNumber);
console.onDestruction(object, function callback() { ... });
...
```
Comment 6 Joseph Pecoraro 2016-10-11 15:31:34 PDT
(In reply to comment #3)
> One nice thing about the "alive + dead" display is that it allows you to see
> memory usage go up and / or down between snapshots.
> 
> Today, since old snapshots update when new snapshots are taken, they
> retroactively edit their total memory usage numbers, erasing debugging
> history.

The Snapshot List view shows both the original Size and the Live Size. The original Size never changes. When viewing the live objects within the snapshot, the Retain Size percentages are based off of the original Size not the current Live Size.


(In reply to comment #5)
> My perfect debugging scenario for what I was trying to do would go like this:
> 1. Take a snapshot
> 2. Pause JS execution
> 3. Find an object inside the snapshot
> 4. Ask the inspector to notify me when it gets destructed
> 5. continue JS execution
> 
> alternatively, some API for doing this like:
> ```
> let object = new Array(someLargeNumber);
> console.onDestruction(object, function callback() { ... });

This sounds very similar to the mark/paint feature request:
<https://webkit.org/b/154410> Web Inspector: Programmatically mark/paint objects for heap snapshot

If you could console.mark(object, "Tag") and then search for all the objects with "Tag" in the Snapshot, that would make it easy to find the object in and across snapshots.

What is it you want to actually do with the object once you've seen it was collected. Just log?
Comment 7 Geoffrey Garen 2016-10-11 16:01:26 PDT
> Showing the dead objects in the tree was very distracting though, since we
> couldn't preview what they were. On even a small page, there could be
> hundreds of objects cluttering the object graphs.

Perhaps we could fix this by making live vs dead an option. I can imagine situations where I would want to focus on one or the other.

Another option would be to snapshot object previews at snapshot time. So, if an object had properties { A, B } at snapshot time, and then acquired a property C => { A, B, C }, the snapshot would still show { A, B }.

Some of this goes to the question of what "snapshot" means. Something that updates over time is not a snapshot -- so it may be a misleading word for our current feature. Our current feature is a bag of objects that grows or shrinks as those objects acquire properties or die.

> Would it help to have a live and dead memory total, but only have the tree
> show the live objects?

Yeah, that might help. It might also help to groups dead objects into some more compact form that doesn't clutter the UI, but still indicates that a bunch of your snapped objects die.
Comment 8 Saam Barati 2016-10-11 20:32:18 PDT
(In reply to comment #6)
> (In reply to comment #3)
> > One nice thing about the "alive + dead" display is that it allows you to see
> > memory usage go up and / or down between snapshots.
> > 
> > Today, since old snapshots update when new snapshots are taken, they
> > retroactively edit their total memory usage numbers, erasing debugging
> > history.
> 
> The Snapshot List view shows both the original Size and the Live Size. The
> original Size never changes. When viewing the live objects within the
> snapshot, the Retain Size percentages are based off of the original Size not
> the current Live Size.
> 
> 
> (In reply to comment #5)
> > My perfect debugging scenario for what I was trying to do would go like this:
> > 1. Take a snapshot
> > 2. Pause JS execution
> > 3. Find an object inside the snapshot
> > 4. Ask the inspector to notify me when it gets destructed
> > 5. continue JS execution
> > 
> > alternatively, some API for doing this like:
> > ```
> > let object = new Array(someLargeNumber);
> > console.onDestruction(object, function callback() { ... });
> 
> This sounds very similar to the mark/paint feature request:
> <https://webkit.org/b/154410> Web Inspector: Programmatically mark/paint
> objects for heap snapshot
> 
> If you could console.mark(object, "Tag") and then search for all the objects
> with "Tag" in the Snapshot, that would make it easy to find the object in
> and across snapshots.
> 
> What is it you want to actually do with the object once you've seen it was
> collected. Just log?

For my use case I wanted to just confirm that it was collected. I basically wanted an intuitive way of finding out that information that didn't require digging through a snapshot. So I think this other proposal would make that easy. I want Inspector to *tell* me that something has died, instead of me inferring that by seeing that the particular object I'm interested in is not in a particular snapshot.
Comment 9 Joseph Pecoraro 2016-10-11 20:47:20 PDT
(In reply to comment #7)
> > Showing the dead objects in the tree was very distracting though, since we
> > couldn't preview what they were. On even a small page, there could be
> > hundreds of objects cluttering the object graphs.
> 
> Perhaps we could fix this by making live vs dead an option. I can imagine
> situations where I would want to focus on one or the other.

Showing dead objects is a great feature and would not be hard to do. I think the most difficult part would be deciding how to approach this in the UI.


> Another option would be to snapshot object previews at snapshot time. So, if
> an object had properties { A, B } at snapshot time, and then acquired a
> property C => { A, B, C }, the snapshot would still show { A, B }.
> 
> Some of this goes to the question of what "snapshot" means. Something that
> updates over time is not a snapshot -- so it may be a misleading word for
> our current feature. Our current feature is a bag of objects that grows or
> shrinks as those objects acquire properties or die.

The behaviors that exist right now are because the current feature is geared (and biased) toward investigating leaked / abandoned objects. "Snapshot" is accurate with respect to the references / relationships between objects. That relationship graph doesn't change, only our view of the objects inside it.
Comment 10 Geoffrey Garen 2016-10-12 11:51:42 PDT
> "Snapshot" is
> accurate with respect to the references / relationships between objects.
> That relationship graph doesn't change, only our view of the objects inside
> it.

Are you saying that snapshots do not update as objects gain and lose properties? I believe they do.

In this example:

var o = { A, B }; // snapshot 0
delete o.A // snapshot 1

Do snapshot 0 and snapshot 1 agree on the properties of o, or does snapshot 0 show { A, B } while snapshot 1 shows { B }?
Comment 11 Joseph Pecoraro 2016-10-12 12:16:50 PDT
(In reply to comment #10)
> > "Snapshot" is
> > accurate with respect to the references / relationships between objects.
> > That relationship graph doesn't change, only our view of the objects inside
> > it.
> 
> Are you saying that snapshots do not update as objects gain and lose
> properties? I believe they do.

Nope. Again, snapshots only gather data about the relationships (strong references) between objects. Snapshots do not save the state / values of objects (it totally skips over primitives).

When you _view_ a Snapshot in Web Inspector we display the live instance, not the state of the object when it was snapshotted, because we didn't gather that information. If we were to to serialize a snapshot of every object when the snapshot was taken that would be quite a lot of data, especially when for detecting leaks the object is still alive, so having the capability of interacting with the live leaked object is more useful.

> In this example:
> 
> var o = { A, B }; // snapshot 0
> delete o.A // snapshot 1
> 
> Do snapshot 0 and snapshot 1 agree on the properties of o, or does snapshot
> 0 show { A, B } while snapshot 1 shows { B }?

This depends on what you mean.

When Viewing Snapshot 0:

    - There is an Object `o`
      - The Live display shows { B }
      - Expanding the Object in the snapshot shows properties "A" and "B" holding onto objects|strings `A` and `B`
        - There is a Live display of B
        - A may be collected so we show that the object was collected
          - You can even get information about how A was kept alive (in this case, via o)

When Viewing Snapshot 1:

    - There is an Object `o`
      - The Live display shows { B }
      - Expanding the Object in the snapshot shows one property "B" holding onto an objects|string `B`
        - There is a Live display of B

So yes, the individual display of `o` shows the live value, but expanding the Snapshot Object Graph shows the Relationships that existed when the Snapshot was taken.