[MUSIC PLAYING]
DAVID HERMAN: Hello, everyone.
Welcome to the deep dive
into Android Studio Profilers
session.
I'm David Herman.
SHUKANG ZHOU: I'm Shukang Zhou.
We are engineers
from the Profiler
team in Android Studio.
DAVID HERMAN: So before
we really got into it,
we wanted to give
you all an outline
of what to expect in this talk.
Instead of sort of coming
from a high overview,
instead we're going
to more narrowly focus
on a few features that we
think can help you get a better
handle on any codebase.
We're also going to drop some
tips and tricks along the way.
We're going to be profiling
a real app, Santa Tracker.
Santa Tracker is
an app by Google
which allows users to
track Santa on his course
around the world
on Christmas Eve.
The app also contains games,
and a couple of other extras.
They release a new
app every year.
We're going to be
using the one that is
publicly available on GitHub.
Finally, I want to mention
two talks about profilers
that were previously given
this year, one at Google I/O,
which did talk profilers
at a higher level,
also introducing what
was new in Android Studio
3.2 for profilers.
And another one at
the Android Game Dev
Summit, about
profiling your games.
That talk focuses
a little bit more
on performance, native
code, related tools,
things like that.
You can find those
videos on YouTube.
If you're watching
this online, we've
also included links to those
videos in the video description
below.
If this is your first time
learning about profilers--
you're just curious--
here's a very quick overview.
The Studio Profilers
feature is divided
into four main profilers,
one for CPU, one for memory,
one for network,
and one for battery.
There's also an
Event Profiler that's
always on the top, which
lets you see things
like user events such as
taps, keyboard events, screen
rotations, and
lifecycle events--
so when you're fragments and
activities start and stop.
Anyway, that's enough talking.
Let's jump into the demo.
SHUKANG ZHOU: OK,
let's start the demo.
So first, with one click on this
button, I can launch the app
and start profilers.
So today, we are
using Android Studio
3.4 Canary 3, because that's
the latest of what we have.
Since this is a Canary release,
it's not a stable release yet.
So there might be some bugs.
Please bear with us if anything
interesting happens today.
The app we are using
today, the Santa Tracker,
contains only Java code.
So the Java apps will be
the focus of today's talk.
So as you can see
in the profiler,
we have four profilers, CPU,
Memory, Network, and Energy.
You can click on any of them
to get more detailed data
from that profiler.
Let's jump to the CPU profiler.
So here, as you can
see in the CPU profile,
you can see the CPU utilization
and the thread state.
It will be useful
to tell you when
your app becomes CPU-bounded.
And if you are examining two
related threads, one trick is--
here--
you can reorder the
threads any way you want.
To know further data information
about which part of your code
is executing, or how
they are executing,
you need CPU recordings.
And let me get a
little bit more space.
So as you can see
here, there are
four types of CPU recordings.
So let's go to the first one.
It's the sample Java method.
Let's get a quick
recording on this one.
So during this type
of CPU recording,
the Java Virtual
Machine periodically
will collect the call stacks
of all the other Java threads
in your process.
And then it will
present the stacks
in this part, which is the
details of the recording.
And after the recording is
done, the entire recording
is automatically selected.
And if you want to
take a closer look,
there is a button called
Zoom to Selection.
So if I click it, it will
fill the entire screen.
And if you want to just see
a subrange of the recording,
you can select using your mouse.
If you want to select the
entire recording again,
you can click this
small clock icon here.
And sometimes you only want
to see a very specific point.
In that case, you can to a
single click in this area,
and you automatically
select something here.
Now let's take a look
at the call stacks here.
And let's select this range.
That might be more interesting.
So as you can see,
the profiler will
color the cost from the Android
platform in orange, the method
from the Java language
in blue, and it will also
color any of your code and
the library code to green.
So if you want to know
what method from your code
is running, you will be
looking for the green stuff.
So here we see some
green stuff here.
And here, if you can see,
this is onDraw method
from the Village View class.
And if you see the codebase,
as you can easily see,
the visit [INAUDIBLE] is
responsible to draw the clouds
that is on this screen.
So another thing I want
to talk about the sampling
is you can do some customization
about this recording type.
So you click this Edit
Configuration entry,
and you can click
this plus sign.
You are able to create
customized CPU configuration.
For this sample Java
method recording type,
you can change the
sampling intervals.
So as most sampling
techniques go,
the more frequently you
collect samples the more likely
the data will be representative.
However, that will
incur more overhead.
So sometimes, depending
on your use case,
you may want to
have several tries
before you find the sweet spot.
So as we have seen,
the sample Java method
is very useful to get a
high-level picture of which
part of the code it is running.
In some other
scenarios, if you want
to focus on a smaller
area, the second type
of the recording,
trace Java method,
will be more interesting.
So let me collect another case.
So in this type
of CPU recording,
the Java Virtual Machine is
collecting the data every time
when the execution enters
a method or exits a method.
So therefore, there is a lot
more data being collected.
So for example, if you really
want to try and understand
exactly what methods
from my code are running,
I will look for the
green stuff here.
And you can see there
are a lot of things.
And you may want to zoom in.
So you can use the
W-A-S-D keys to zoom in.
So the W will be the zoom in.
As you can see, the
key I'm pressing.
The S will be zoom out.
The D will be
moving to the right.
A will be moving to the left.
So if you're a gamer, you
probably already know this.
If you zoom in,
let's keep zooming in
to see what are
these green stuff.
So here we seen
in this, a big one
is the one we just saw before.
It's the onDraw method
from the Village View.
They are responsible
for drawing the clouds.
Here, this is the onDraw method
from the Snowflake View class.
They are responsible to draw
all these snowflakes that
are floating around.
And if you look closely, there
are many very tiny green lines
here.
So you can further zoom in.
You can further zoom in.
So you can see this
is the onDraw method
from the Snowflake class.
This is also from
the snowflake class.
This is also from
Snowflake class.
So you may want to see what
exactly does this class go.
So you Right-Click here,
and you can have a menu
to jump to the source code.
So you can see here, in
this Snowflake class,
in this onDraw
method, we are doing
some calculation about the
velocity, about an angle,
about the size.
Then we draw a circle.
Then it's clear that every
snowflake on this screen
will execute this method.
That's why we are seeing so
many calls into this method.
So as you can see,
trace Java method
is very useful to
verify whether or not
a method has been executed.
It's also useful to verify how
often that method is executed.
Another thing I want
to talk about here
is about the four caps here.
So the first one
is the call chart.
So the call chart,
as we said, is
representing all the call
stacks during the CPU recording.
So the things to the left--
well, let's select
the entire range.
You can see it.
So the call stacks
show up the left,
where it happens first
in this recording.
So the things to the right will
happen later in this recording.
In the frame chart,
it7s similar to the call
stacks, but it's upside down.
So the root is at the bottom.
And also, identified call
stacks are aggregated here.
So it's very easy to see
the total time of method
has been executed.
The top-down is [INAUDIBLE]
has exactly the same data
as the frame chart.
It7s just represented
in a different view.
So what's nice
about this view is
you can sort of these
methods by the time.
So the save time is
the time executing
by this method itself.
The children is the time
executed by the subroutines
called by this method.
And the total column is
the combination of the two.
Bottom-up is looking at the call
stack upwards to the caller,
basically from the method
to another function that
called it.
So here, it's very useful.
If you expand it,
it's very useful
to see where this
method is called,
and how much time this method
has executed when it is
called by that specific caller.
And there is a third
type of CPU recording
that is sample
native functions--
C or C++ functions.
And let's do also
another short trace here.
And if you remember, I just
said this app, Santa Tracker,
it contains Java-only code.
So therefore, the call stacks,
assuming the call stacks
collected by this
type of recording
is not very interesting.
They are mostly
the system calls.
Some of them use the Android
framework native code.
So however, if your app
has any native components,
this type of recording
will be very handy.
There is another type of CPU
recording called trace system
to our calls.
But before I go into
the details of that,
I will hand the
demo back to Dave.
DAVID HERMAN: Excellent.
So CPU recordings
are very useful.
However, sometimes there's an
exact function, or maybe just
a couple of functions that
you know you want to analyze.
And it's a little bit imprecise
to record, do something
in your app, stop recording,
and then zooming in
and search for it.
Fortunately, we provide a
very simple solution for this.
And I already added the code in.
So let's talk about it.
So the debug class is actually
part of the Android API.
And the debug class
and many of its methods
have, in fact, been
in the Android API
since the very first
version, including these two.
What the start method
tracing function does
is it asks the system
to take a trace,
save it with the filename you
provide, and then it puts it
in a folder somewhere that you
can pull off your device later
and inspect.
That's really nice, but
on Studio profilers,
we've got your back.
We'll do all of
that work for you.
So if you were
doing this manually,
you'd probably be very careful
about the name that you chose.
And if you're doing
multiple traces,
you'd maybe choose
unique names so that they
didn't overwrite each other.
In our case, the name is not
going to show up in Studio.
We don't really care about it.
So call it whatever you want.
Here, I'm going to start
doing it putting a recording
around this function.
So what I'm curious
about in this case,
there's an activity in Santa
Tracker called the City Quiz.
And the City Quiz loads
files from the disk.
That's usually a
really good thing,
where you want to know how
long it's going to take,
and if it's doing
anything suspicious.
Maybe it's not.
We're going to take a look.
But one thing I
do want to mention
is when you call this start
method tracing function,
it's doing a trace of your code.
This is the more expensive,
precise, detailed one.
So I'd be very careful.
I wouldn't do this around
a large amount of code,
just to make sure
that it doesn't take
longer than you might expect.
All right, let's actually
go into the City Quiz,
which is down here.
See what happens.
Now, before I do this, I want
you to keep your eye over here
in the Session panel.
And you hit Play.
It7s going to run in.
And it's automatic
going to record.
I didn't have to do anything.
That's awesome.
Let me back out.
So as you can see here,
there's nothing new.
This is exactly what Shukang
was just showing you before.
It's just another trace.
But you didn't have
to record it yourself.
I think this is a good
moment to call out
the lifecycle events
I talked a little bit
about at the
beginning of the talk.
As you can see, we're
doing a load here.
We left our previous activity.
And now we're into
this new activity.
You can also see that if you put
your mouse over an activity, as
of Android Studio 3.3, it will
also include the fragments that
are active during that time.
So that may be useful for you.
But here we are.
We're in this space
while we're still
loading, before we've
actually entered the activity.
And there's another
really great feature
that I want to show you here,
which is this Filter button.
When I press the Filter button,
it brings up a search box
where I can type into it.
Now I happen to
know that JSON has
a function called readLiteral.
So let me just type that in.
Now one thing you
might notice here
is this part of my
call chart dimmed out.
And all parts here are not dim.
They're still the normal color.
So let me zoom in and see
if I can find where that is.
So there we go.
So we could see some instances
of this readLiteral function.
Basically if my function is
an exact match, it will bold.
If it's a function that calls
either into that function
or is called out of that
function indirectly,
the color will be left the same.
And otherwise, it will dim.
And it's really
useful to sort of get
a good overview of
how much time you're
spending in your
code on the function
that you care about
versus what you
don't have to pay attention to.
All of the CPU detail
views support this.
So the flame chart has
this similar dimming.
Top-down and bottom-up will
strip out those functions
that were dimmed.
So if you're ever trying to
inspect some sort of method,
and you're really
narrowing down on it,
please give the
filter option a try,
and see if you can sort of
focus on what you're looking at.
Now the last thing to
call attention to here
is, all of these
traces that we've done,
if you mouse over them,
there is a Save button here.
So you can actually
export your traces.
If you do this, you can
give it to a co-worker,
attach it to a bug--
useful things like that.
If somebody gives you a trace
file or you are loading one,
you can just hit the plus
button over here, and load it
from file.
All right.
OK, cool.
SHUKANG ZHOU: Now
I'm going to talk
about the last type
of CPU recording,
the trace system calls.
Trace system calls,
on this feature,
was introduced in Android 3.2.
It collects fine-grained
system events
that's related to an
app7s performance.
So you can investigate how your
app interacts with the system
resource so that's
a system trace.
So one thing-- again, I'm
using the Click to Zoom button
here so that it's
very easy to see.
One thing I want
to show you here--
the first thing I
want to show you
is in this thread state view.
So if you click the range,
zoom to that selection again,
and I will click here.
[INAUDIBLE]
So here, as you can see, you
can use your mouse, hover over,
you can see this thread state
is runnable, become running,
then become runnable,
become running again.
So as you can see, we are
collecting every CPU scheduling
operation.
So at this level of details,
it's very easy for you
to figure out exactly when
your thread becomes blocked.
And that could be useful if
you have some threading issues.
Another thing I want to show
using the trace system costs
is to investigate slow UI jank.
So slow UI rendering, also
called jank by some people,
as you may know, that
is the [INAUDIBLE] UI
does the work in two phases.
The first phase happens
in the main thread.
It determines what
is on the screen,
including the layout
and the [INAUDIBLE]..
It determines the what
by executing all the UI
elements, such as all the
view classes in your app.
So after the main threads
generate the what,
they are passed to the
native render thread.
The render thread will be
figure out how to draw them.
Then the how will be passed
to the surface finger system
process, and the
hardware who is actually
performing the drawings.
So that is giving
that background
so we can see under
the frame area,
we have this main, which
represents the main thread,
the render represents
the render thread.
So let me zoom out a little bit.
So you can see here,
this is the first phase.
And corresponding, the
second phase will be here.
If you are targeting
a smooth UI--
smooth animation at
60 frames per second,
which is roughly 16
milliseconds per frame.
So the two phases
combined together
should be under 16 frames.
If it is longer than
that, the profiler
will color that frame to red.
So as you know, this
is something slow.
So if we zoom out more, you
can see a lot of frames.
I think every one today is red.
That means every
one is exceeding
the 16 millisecond threshold.
One factor is we are
using the emulator.
Because the way the emulator
interacts with the system,
you are going to
see more red frames
than from our actual device.
Before today's talk, I have
collected another trace
using an actual physical device.
And I have exported
that trace as a file.
And now I want to import
that trace to show you.
So as Dave said before,
you can use this plus sign
to import a trace.
That7s this trace.
Because when you
trace system calls,
everything-- the system-wide
events are collected.
So you need to tell
the provider which
process you want to look at.
So we want to look
at Santa Tracker.
And as you know, the Linux
from the system point of view,
every process or every
thread, your name
can be no longer
than 15 characters.
So that's why this
one is actually
the santatracker.debug.
For some reason, the system
thinks this is the name.
So if you select this one, you
are going to import this trace.
And here, you can see
from the actual device,
most of the frames
will be in gray.
That indicates that they are
under 16 millisecond threshold.
And so6e of the
frames are in the red
because they are
over that threshold.
You may wonder, how does
the profiler know how
long these phases are taking?
That is from the tracing point.
So Android platform
engineers have
added building tracing points
into some of the critical tasks
in the Android system.
So the example here is, if you
click the main thread here,
these events are showing
from the trace events here.
So if I zoo6 in here,
you will see this.
These are trace event called
Choreographer doFra6e.
So that's the first phase
we just talked about
in the UI rendering.
It happens in the main thread.
If you click the
render thread, you
can see there is an
event called drawFra6e.
So that's the second phase.
And you can also
see there are other
tracing points in the system.
They are all building syste6s.
So they are available
on any Android phones,
because they are building.
And they are very useful to
get the timing information
for some specific tasks.
And actually you can have
your own trace points, too.
And I'm going to demo that here.
So today-- so here,
if we go into the top
of the app, come back to
this view, we have the cloud.
We have the snowflakes.
I want to know exactly how long
6y code is spent joining them.
So for the cloud, I go
to the Village View.
So there should be
a onDraw method.
So at the beginning
of the method,
I add the instrumentation.
The trace beginSection, you
need to provide a string,
which is the section's name.
At the end of the method, I
will end this trace event.
For the snowflakes, it
goes to the Snowflake View.
Again, it should be
in the onDraw method.
I want to point out
the section name.
You should pick
a name that 6akes
sense to you so you
can recognize when
you7re doing the CPU recording.
So here we are doing the
Snowflake Android Dev Su66it
2018.
So that makes sense
for today's demo.
So now I have added the
manual instrumentation.
So I will rebuild this
app, and re-profile it.
So while we are waiting for the
build, you may be wondering,
if I want to know how long
the two methods are taking,
why don't you use the
trace Java method,
that type of CPU recording you
are talking about a moment ago?
So I would say trace Java
method is very powerful.
It's very easy to use.
But it has significant overhead,
because the Java Virtual
Machine is collecting data every
time when the execution enters
a method, and every time when
the execution exits a method.
So if you have a lot of
frequent small method calls,
that overhead can quickly add
up and become very expensive.
If you use the 6anual
instrumentation,
for example like
using the trace API,
you have the full control of
when and where to collect data.
So if you use that wisely, the
overhead will be much smaller.
And as a result, the
data you collected
will be more accurate.
So let's verify the
instrumentation we have.
So you go to the CPU Profiler.
We collect a trace of
trace system calls.
And here, we zoo6 in.
We see this event again,
choreographer doFra6e.
This is from the main thread
that is responsible for all UI
elements.
And if you keep
zoo6ing, you can see
this is the frame we just
added, Village View, who
is joining the cloud.
And this is the
Snowflake View, ATS 2018.
That's the thing responsible
for joining the snowflakes.
So this is how to use the trace
system calls CPU recording.
So you may have heard of a very
similar tool called systrace.
So actually my Google
co-worker [INAUDIBLE]
gave a lightning talk
yesterday on the systrace.
So it's an extremely
powerful tool,
but the learning
curve of the systrace
is a little bit steeper than
the Android Studio Profiler.
So you may choose the tools
that best suits your needs.
OK, that's for the
trace CPU recording.
I will hand over the
demo back to Dave.
DAVID HERMAN: All right.
Let's leave the CPU Profiler
behind, and jump over
to the Memory Profiler.
First of all, I want to
draw everyone's attention
to this allocation
tracking pull-down.
Some quick history here,
in Android Studio 3.0,
when targeting Android devices
with O or newer, what we did
is we would collect a call stack
for every single allocation
that your app made.
We did it because it would
be very convenient to use
to have that history.
However, some of our users
reported that profilers
were slowing their app down.
After we investigated, it
turned out to be this feature.
So starting in
Android Studio 3.3,
we now give you the
option to configure this.
Let me go ahead and look here.
So we have None,
Sampled and Full.
None disables the
feature, Full enables it,
and Sampled attempts to collect
a subset of the allocations.
That sort of gives you a general
look for how your app7s memory
behavior is, while not actually
affecting your performance
as much as a full one does.
Now that being said, whether
or not Full affects your app
or not can depend
on the host machine
you're running
on, whether you're
targeting a device or an
emulator, or even your code.
If your app code has a
lot of small allocations
in it like Santa Tracker
does, it can be slow.
But I recommend playing
around with the features.
I'm going to go ahead
here and turn Full on.
I76 going to go live here.
So you notice once
I turned on Full,
this allocation indicator
started showing up.
I want some interesting
things to happen.
So I'll just go ahead
and rotate the device.
I may grab you there.
Rotate it back.
move it back over there.
So now let's go ahead
and take a look here.
So all I need to do at any
point is just drag across,
and I'm going to
be able to see all
of the allocations
and the deallocations
that happened during that range.
This could be a
really lightweight way
to sort of get a quick look
at what your memory is doing.
There's an allocation
and deallocation count.
So sometimes you might be able
to find memory leaks even just
doing this.
And then the other nice thing
is maybe if you have this on,
and you're doing
some other stuff,
you can actually go back
in time and select a range,
and still see what's
going in your memory.
Now I'm going to go ahead here
and turn it back off again.
And you'll notice that
the allocation indicated
that it stopped tracking
by doing an empty circle.
If I did Sampled Mode, it
would put a half-filled circle.
Now looking at these
objects, once I click on it,
you can see every single one
that's currently allocated,
as well as where
it was allocated.
This is very useful to get
your handle on a codebase.
You can click around this and
see where different objects are
coming from.
That being said,
it might not help
you understand why a
memory leak happened, what
is holding on to my memory.
If you want to get
that information,
you have to go over
here to this icon--
this is the heap dump icon--
and click the heap dump.
So what I'm actually going to
do here, just to let you know,
I could not find a leaking
activity or fragment
in the Santa Tracker app.
So, full disclosure,
I added one.
And what I did is I
added a memory leak
to this Penguin Swim game here.
So actually let's go ahead
and go into the activity,
and leave it.
And let me actually
do another heap dump.
All right, so we're about
to get a bunch of heap dump
information here.
So I know that the fragment
inside this activity
is called swim fragment.
So just like CPU, we have
the Filter button here.
And I can filter out all
of the different objects,
and find that, yep, sure
enough, this swimming fragment
is still alive.
And I'll click on it, I'll
select the active instance.
There is a lot going
on here, so I'm
going to take a moment to
sort of explain a little bit.
And let's just take a step back
and take a moment to absorb it.
So I really want to explain
what this depth idea is.
So imagine all your
Java memory that
can be cleaned up by the garbage
collector lives in this heap.
There are some special
Java objects that
live outside of this circle.
Those are called GC roots.
When you create a new
thread, that basically
creates this special GC root.
Or static variables are
an instance of a GC root.
So what ends up happening
is you might, in a thread,
create an instance of some
class that it, in turn, creates
an instance of
another class, and it,
in turn, so on and so forth.
And so basically
what you're doing
is you're creating this
long chain of objects,
and each item in that chain
has further and further
depth from the GC root.
Now you may have heard that
cycles are not a problem
to the garbage collector.
I can point at you, and
then you point at you,
and you point back at me.
But if we can't all
be reached, that
will all get removed by
the garbage collector.
So one of the things to note
is when you take a heap dump,
you might see a scary
amount of things
holding on to my instance, but
a lot of those are harmless.
A lot of them are
potentially just cycles.
And one way that you can kind
of know-- it's not always true,
but it's a good heuristic--
is if the depth is greater
than your own depth.
So let me explain why that is.
So imagine that the garbage
collection root points to you.
You create a child instance.
And one of the things you do is
you give it your this pointer.
So it's pointing back at you.
That's a very common thing.
Here, you point back at me.
You're my child, but you
know who your parent is.
So that means my
depth is then going
to be added onto that
this pointer's depth.
So that's a reason that
some of these depths
here may indicate that
even though you're
seeing that it's not an
issue, you'll also notice here
that there's a few of these
items in the depth column
where the depth is blank.
That means that
there's actually no way
to reach these at the moment
from any garbage collection
root.
So it will eventually
be cleaned up.
Even though it's showing up
in the heap dump right now,
you don't have to
worry about it.
Just ignore it.
It's as good as reclaimed.
Just to make sure we
understand this a little bit,
with a concrete
example, I'm actually
going to look here at
this code, which is not
the cause of our memory leak.
Our depth is 1.
This item's depth is 2.
So what this is
saying is somewhere
there is an instance
of a score view class.
And that score view class
has a variable called share
ClickListener,
whose value is me.
So let's go ahead and take
a look at swimming fragment.
And I'm going to search
for getScore view.
So before, when I saw
this, I was trying
to look through the code.
I said, there's
gotta be some way
that I'm going to get a
score view that points at me.
And there's this
getScore view method
inside my swimming fragment.
If I jump to it, what
you're going to see is, yep,
we create one, and we
pass in the this pointer.
So that's sort of explaining
why there is a cycle there.
I don't have to worry
about it, but at least it
sort of explains why it's
showing up in the heap dump.
Now you'll also notice there's
a lot of this$0 symbols.
What's going on here--
because you're going
to see it a lot.
You all know what
the this pointer is,
but if you are an inner class--
if you're a nested class
and you need to have access
to your outer classes' fields,
the way that it
works is the compiler
generates a synthetic variable.
And instead of calling it
this, because that's taken,
it calls it this$0.
So this$0 means the this that's
one level out of my scope.
And any time you create
an inner class that
has a reference to
its outer class,
or you create a closure, an
anonymous class instance,
it's going to have that.
So if you're all using
lambdas in your code,
or anonymous
classes, you're going
to see a lot of these zeros.
This one has a depth of 0,
which means it's a GC root.
That makes it really suspicious.
So let's jump to the source.
Now hopefully I
might look at this
and say, oh, I wrote
this long-running task.
As you can see, it's
not a static class.
It's a final class.
So if it's not static, it's
going to hold onto a reference
to the parent class.
That's what's going on here.
And I might say, oh,
this long-running task,
I created it, but I
forgot to cancel it.
So let's go ahead
and take a look here.
Yep, sure enough, I
left it commented out
for no good reason.
Let me uncomment it there.
And let's relaunch.
So what we're going
to do now is--
let me just make
sure it's saved.
There we go.
What we're going to do
now is reboot it just
to make sure that in fact this
swimming fragment was released.
One of the things
to keep an eye out
for when you're hunting
for memory leaks
is static variables
or singleton classes
that are holding onto your
class or registering yourself
with a listener, but
forgetting to remove it,
or any of these inner
classes that for some reason
may not end up stopping.
And they're still running,
even though the activity
is trying to exit.
Are we profiling here?
Yes, we are still going.
And then another thing
I want to mention
is it's not always
going to be this easy.
You're not always going to
have this obvious culprit.
So in that case,
what you're going
to want to do is,
I would say, just
try to get to know the code.
Look for those things
that I talked about.
Let's go ahead and enter.
And we'll exit
here while I talk.
And if you've cleaned it up,
even if you didn't find it
through the heap
dump, the heap dump
is still going to be
the source of truth.
It's still going to
be the thing that
guarantees to you that your
memory is actually reclaimed.
So I'm going to go
ahead here, go back
into the memory profiler.
I'm going to click on
the garbage collector.
So you may have noticed these
garbage collected events,
automatically at the bottom.
So for example,
there's a lot there.
That's when the
garbage collector
decided to collect on its own.
But you can also click the
garbage collection button
to manually cause it to get run.
Now we still see
swimming fragment here.
Let's see if the
depth is actually--
so as you can see,
swimming fragment
is still showing up, which is--
I could be nervous.
What happened?
But the depth column
here is blank.
Everything is just
basically waiting
to be picked up by
the garbage collector.
You can press the garbage
collector a few more times.
One trick I like to do
is rotate the phone,
and then rotate it again.
Anytime you rotate an Android
phone, lots of fun things
happen.
It tells the garbage
collector things are going on.
So in that case, let's just
do another heap dump here,
and we'll see if the
swimming fragment is
truly well and collected.
I wish this came
with a drum roll.
And there you go.
It's gone.
So the final thing I want
to quickly talk about
is, if you're looking
at the heap dump,
you're not always necessarily
hunting a memory leak.
You might not know some
major class to look out for.
So there's this concept of
shallow size and retained size.
So shallow size is the size of
a single instance of some class
that's been allocated.
And retained size is all of
the things that's holding onto.
So what you may
want to do is hunt--
sort your shallow size,
sort your retained size,
maybe investigate
to see if there's
any sort of suspicious
memory things there,
or maybe you could
clean up your design
and remove some
memory there earlier.
Anyway, that ends our demo.
Hand it back to Shukang.
Let's go to the slides.
SHUKANG ZHOU: OK, cool.
So to recap, in
today's demo we have
shown to use CPU
Profiler and Memory
Profiler to get a better
understanding of the codebase
of the Santa Tracker app.
And to be honest, Dave and
I don't know much about it
before we are preparing
for this talk.
And we also have shown
that we don't only
use profilers to diagnose
performance issues.
We also use the profilers
to help us understand
the performance of this app.
As we said before, there
are also network and energy
profilers in Android Studio.
But unfortunately, we don't
have time to cover them today.
So please refer to our
online documents and talks
to learn more.
So we hope you have learned some
tricks and tips from our demo
today.
We hope they are useful
when you approach
your own codebase with your
Studio Profilers at your site.
Thank you very much
for attending our talk.
[APPLAUSE]
[MUSIC PLAYING]
