New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.
Starred by 15 users

Issue metadata

Status: Assigned
EstimatedDays: ----
NextAction: ----
OS: All
Pri: 3
Type: Bug

issue 536263

Show other hotlists

Hotlists containing this issue:

Sign in to add a comment

Issue 429375: CSS infinite linear animation w/ alpha transparency leaks memory

Reported by, Oct 31 2014

Issue description

UserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36

Example URL:

Steps to reproduce the problem:
1. Open (or open and click the "Toggle animation" button).
2. Leave the browser tab with that webpage open and visible for an extended period.

What is the expected behavior?
Chrome shouldn't leak memory, since the Fiddle contains no significant JavaScript and the JS in the Bootstrap docs is believed to not have any significant memory leaks. And since the leak has been observed even with JavaScript disabled.

What went wrong?
Chrome seems to experience a memory leak, and its memory usage over time increases without bound.

Does it occur on multiple sites: N/A

Is it a problem with a plugin? No 

Did this work before? N/A 

Does this work in other browsers? Yes 

Chrome version: 38.0.2125.111  Channel: stable
OS Version: OS X 10.10.0
Flash Version: Shockwave Flash 15.0 r0

Original Bootstrap issue with some more info:
Other repro URL: (after clicking the "Toggle animation" button, which was added specifically due to this Chrome memory leak!)

The memory leak has been reported by users on both Mac OS X and Windows 7 Pro.

It was originally observed on
A Bootstrap user (@ssorallen) reported still observing the memory leak after disabling JavaScript, hence why we believe this is CSS-related.
The same user also reported that removing the animation CSS from the example animated progress bar avoided the memory leak, hence why we believe the leak is related to this animation specifically.

That user further reported that eliminating the alpha transparency from the color stops seemed to avoid the memory leak.

Comment 1 by, Nov 3 2014

Labels: Needs-Feedback M-38
Unable to repro this issue on MACBookpro 10.9.5 using: 38.0.2125.111 with below steps:

1. Opened
2. Opened chrome task manager and observed the memory usage for above tab

Left the page visible for 30 min and observed no memory link. 

Could you please re-check this issue on clean profile and confirm the same. If issue is still repro, please provide more steps along with chrome://gpu will help further.

Comment 2 by, Nov 3 2014

The fiddle page doesn't leak on Windows 7 in Chrome.

My issue I think isn't w/ the progress bar, it's with the carousel from Bootstrap.

I have a page opened w/ a carousel in Chrome Version 38.0.2125.111 m and over time it eats up memory (it's currently @ 1 Gb, according to the Chrome Task Manager.  The same page is stable 235 Mb in Firefox.

I hope this helps.

Comment 3 by, Nov 4 2014

Well, Ross observed a memory leak even with JavaScript disabled, so that would suggest that there's a non-Carousel-related leak.

(Not saying it isn't possible for the Carousel to have its own additional leaks though.)

Comment 4 by, Nov 6 2014

Labels: Cr-Blink-Animation Performance-Memory

Comment 5 by, Jan 12 2015

Labels: -Type-Compat -OS-Mac -Needs-Feedback -M-38 Type-Bug OS-All M-41
Status: Untriaged
Able to reproduce the issue on Windows and Linux as well, please review attached screenshot. This is a Non Regression issue seen from 26.0.1410.56.

Comment 6 by, Jan 12 2015

197 KB View Download

Comment 7 by, Jan 15 2015

Labels: -M-41 M-42 MovedFrom-41
Moving all non essential bugs to the next Milestone.

Comment 8 by, Mar 3 2015

Labels: -M-42 MovedFrom-42
[AUTO] This issue has already been moved once and is lower than Priority 1,therefore removing mstone.

Comment 9 by, Mar 12 2015


Comment 10 by, Mar 12 2015

Labels: -Pri-2 Pri-1 M43 Cr-Blink-Performance
This appears to be quite a severe issue. Looks like high memory & CPU usage. Someone should take a closer look.

Comment 11 by, Mar 12 2015

Comment 12 by, Mar 12 2015

Labels: -M43
Status: Available

Comment 13 by, Jul 15 2015

Labels: -Cr-Blink-Performance Performance

Comment 14 by, Sep 26 2015

Blocking: chromium:536263

Comment 15 by, Oct 5 2015

@rschoen I was able to repro pretty high CPU usage for this in M47 and it's still causing Bootstrap quite a few performance issues in Chrome. Would a member of your team have time to take a look at this one?

Comment 16 by, Dec 30 2015

Owner: ----

Comment 17 by, Mar 3 2016

I'm able to reproduce this consistently when having a backface-visibility: hidden applied to the element. See my codepen:

I'm on OSX 10.11.3 and Chrome 48.0.2564.116

Comment 18 by, May 26 2016

Labels: Update-Monthly

Comment 19 by, May 26 2016

Labels: -Update-Monthly

Comment 20 by, May 26 2016

Labels: Update-Monthly

Comment 21 by, Jun 27 2016

This has been open for a while, so I'm attempting a fresh repro with Chrome unstable (53.0.2774.3) on Linux.

The minimized test case in #11 doesn't seem to be showing any memory leak for me, but I am seeing a gradual increase in memory in from the original report and in the extra report in #17.

Comment 22 by, Jul 28 2016

Status: Assigned (was: Available)

Comment 23 by, Aug 11 2016

I've investigated this further on Canary using chrome://tracing (following

One thing I've found which looks curious is in the "Memory per component" graph for the tab, showing a gradual increase in the "malloc" category. According to the above .md file that means "Memory allocated by calls to malloc, or new for most non-Blink objects." Drilling down into that component, most of the memory is in the unhelpfully-named "allocated_objects" > "<unspecified>" section.

I tried "tools/valgrind/ -v out/GnRelease/content_shell" (with use_allocator=none in my gn args, as advised by Nothing stood out to me, but I've also never really done this before.

I'm at a loss for how to investigate this further. Passing over to haraken from the memory team.

haraken, any advice?

Comment 24 by, Aug 11 2016

We need to identify what objects are leaking in malloc, but the information is not (yet) available in the current memory-infra.

tasak@, dskiba@: Should we try the native-stack profiler to identify objects & stack traces leaking in the page?

Comment 25 by, Aug 11 2016

Yes, definitely, if we saw that malloc increases, the next step to use native heap profiling, as outlined in

The only catch is that native heap profiler works only on Linux / Android for now.

Comment 26 by, Aug 12 2016

Components: -Blink>Animation Internals>Compositing
Labels: -Update-Monthly
I applied the heap profiling instructions from that link (just the basic one, without compiling for native heap profiling) and saw what seems to be a large increases in



and nothing significant under third_party/WebKit.

Transferring over to the compositor folks. weiliangc, can you take a look?

Comment 27 by, Aug 12 2016


Comment 28 by, Sep 27 2016

Labels: M-55
vollick@ could you please find an owner for the memory leak in LayerTreeHost::UpdateLayers::BuildPropertyTrees in #26?

vnpstr@ could you please take a lok at the possible TileManager memory leak in #26?

Comment 29 by, Nov 2 2016

Gentle Ping! Since this is a P1 bug for M55, could any one let us know is there any latest update available for this issue? M55 is already in Beta and mostly we are planning to push the same to stable soon in this month.


Comment 30 by, Nov 2 2016

Ali, could you please look at the build property trees issue?

Comment 31 by, Nov 3 2016

I followed the native heap profiling instructions to get traces of each of the three pages from above on ToT Linux:

1) The original page ( is trace_heap1.json.gz (see process 30932)
2) from #11 is trace_heap2.json.gz (see process 21050)
3) from #17 is trace_heap3.json.gz (see process 16408)

For (1), the main increases are in malloc and skia. For malloc, the entire increase (4.5 MB over 20 seconds) comes from the metadata_fragmentation_caches category, and for skia the entire increase (3.5 MB over 20 seconds) comes from sk_resource_cache. Looking at the stacks, allocation from PropertyTreeBuilder stays consistent at ~5 KB throughout, so there doesn't seem to be a leak there.

For (2) and (3) the only increase that stands out is in malloc (4 MB over 20 seconds) and again it's entirely in metadata_fragmentation_caches. (And allocation from PropertyTreeBuilder stays consistent, ~5 KB on (2) and ~13 KB on (3).)

My understanding is that metadata_fragmentation_caches accounts for memory used by the allocator rather than actual objects allocated (or leaked) by code, could someone confirm?

Passing to vmpstr to triage the sk_resource_cache increase in (1).

Comment 32 by, Nov 3 2016

I ran for more than an hour on, sampling with second-long traces several times. So in 80 minutes malloc grew by ~1MiB, and growth came from here:

+992.9 KiB [Thread: CompositorTileWorker1/28018]
+992.9 KiB </system/lib/>
+992.9 KiB ThreadFunc
+992.9 KiB base::SimpleThread::ThreadMain()
+992.9 KiB content::CategorizedWorkerPool::Run(std::__ndk1::vector<cc::TaskCategory, std::__ndk1::allocator<cc::TaskCategory> > const&, base::ConditionVariable*)
+992.9 KiB content::CategorizedWorkerPool::RunTaskWithLockAcquired(std::__ndk1::vector<cc::TaskCategory, std::__ndk1::allocator<cc::TaskCategory> > const&)
+992.9 KiB content::CategorizedWorkerPool::RunTaskInCategoryWithLockAcquired(cc::TaskCategory)
+992.9 KiB RunOnWorkerThread
+992.9 KiB cc::OneCopyRasterBufferProvider::RasterBufferImpl::Playback(cc::RasterSource const*, gfx::Rect const&, gfx::Rect const&, unsigned long long, gfx::SizeF const&, cc::RasterSource::PlaybackSettings const&)
+992.9 KiB cc::OneCopyRasterBufferProvider::PlaybackAndCopyOnWorkerThread(cc::Resource const*, cc::ResourceProvider::ScopedWriteLockGL*, gpu::SyncToken const&, cc::RasterSource const*, gfx::Rect const&, gfx::Rect const&, gfx::SizeF const&, cc::RasterSource::PlaybackSettings const&, unsigned long long, unsigned long long)
+990.1 KiB cc::OneCopyRasterBufferProvider::PlaybackToStagingBuffer(cc::StagingBuffer*, cc::Resource const*, cc::RasterSource const*, gfx::Rect const&, gfx::Rect const&, gfx::SizeF const&, sk_sp<SkColorSpace>, cc::RasterSource::PlaybackSettings const&, unsigned long long, unsigned long long)
+989.2 KiB cc::RasterBufferProvider::PlaybackToMemory(void*, cc::ResourceFormat, gfx::Size const&, unsigned int, cc::RasterSource const*, gfx::Rect const&, gfx::Rect const&, gfx::SizeF const&, sk_sp<SkColorSpace>, cc::RasterSource::PlaybackSettings const&)
+993.6 KiB cc::RasterSource::PlaybackToCanvas(SkCanvas*, gfx::Rect const&, gfx::Rect const&, gfx::SizeF const&, cc::RasterSource::PlaybackSettings const&) const
+994.6 KiB cc::RasterSource::PlaybackToCanvas(SkCanvas*, cc::RasterSource::PlaybackSettings const&) const
+994.6 KiB cc::RasterSource::RasterCommon(SkCanvas*, SkPicture::AbortCallback*) const
+994.6 KiB cc::DisplayItemList::Raster(SkCanvas*, SkPicture::AbortCallback*) const
+994.9 KiB cc::DrawingDisplayItem::Raster(SkCanvas*, SkPicture::AbortCallback*) const
+994.9 KiB SkCanvas::drawPicture(SkPicture const*, SkMatrix const*, SkPaint const*)
+987.1 KiB SkCanvas::onDrawPicture(SkPicture const*, SkMatrix const*, SkPaint const*)
+987.1 KiB SkBigPicture::playback(SkCanvas*, SkPicture::AbortCallback*) const
+987.1 KiB SkRecordDraw(SkRecord const&, SkCanvas*, SkPicture const* const*, SkDrawable* const*, int, SkBBoxHierarchy const*, SkPicture::AbortCallback*)
+987.1 KiB SkCanvas::onDrawRect(SkRect const&, SkPaint const&)
+987.1 KiB SkBitmapDevice::drawRect(SkDraw const&, SkRect const&, SkPaint const&)
+987.1 KiB SkDraw::drawRect(SkRect const&, SkPaint const&, SkMatrix const*, SkRect const*) const
+987.1 KiB SkBlitter::Choose(SkPixmap const&, SkMatrix const&, SkPaint const&, SkSmallAllocator<3u, 3332u>*, bool)
+987.1 KiB SkShader::createContext(SkShader::ContextRec const&, void*) const
+987.1 KiB SkPictureShader::onCreateContext(SkShader::ContextRec const&, void*) const
+987.1 KiB SkPictureShader::PictureShaderContext::Create(void*, SkPictureShader const&, SkShader::ContextRec const&, sk_sp<SkShader>)
+989.1 KiB SkShader::createContext(SkShader::ContextRec const&, void*) const
+989.1 KiB SkImageShader::onCreateContext(SkShader::ContextRec const&, void*) const
+989.1 KiB SkBitmapProcLegacyShader::MakeContext(SkShader const&, SkShader::TileMode, SkShader::TileMode, SkBitmapProvider const&, SkShader::ContextRec const&, void*)
+989.1 KiB SkBitmapProcInfo::init(SkMatrix const&, SkPaint const&)
+989.1 KiB SkBitmapController::requestBitmap(SkBitmapProvider const&, SkMatrix const&, SkFilterQuality, void*, unsigned int)
+989.3 KiB SkDefaultBitmapController::onRequestBitmap(SkBitmapProvider const&, SkMatrix const&, SkFilterQuality, void*, unsigned int)
+989.3 KiB SkDefaultBitmapControllerState::SkDefaultBitmapControllerState(SkBitmapProvider const&, SkMatrix const&, SkFilterQuality, SkSourceGammaTreatment)
+989.3 KiB SkImageCacherator::lockAsBitmap(SkBitmap*, SkImage const*, SkImage::CachingHint)
+988.0 KiB SkImageCacherator::tryLockAsBitmap(SkBitmap*, SkImage const*, SkImage::CachingHint)
+992.0 KiB SkResourceCache::Add(SkResourceCache::Rec*)
+992.0 KiB SkResourceCache::add(SkResourceCache::Rec*)
+992.0 KiB sk_calloc_throw(unsigned int)

(The buffer at the end was exactly 1 MiB).

The only thing SkResourceCache::add() that can cause an allocation is fHash->add(rec), which is SkTDynamicHash<T>::add(). That function calls maybeGrow(), which is implemented this way:

    void maybeGrow() {
        if (100 * (fCount + fDeleted + 1) > fCapacity * kGrowPercent) {
            this->resize(fCapacity > 0 ? fCapacity * 2 : 4);

What is interesting here is that by repeatedly inserting / removing different keys we can drive fDeleted up, causing this function to double the size.

That is confirmed by looking at the skia/sk_resource_cache entries: the number of bitmap-shader_* entries stays the same, but they are different.

The trace is attached, but be warned that the last point is ~5000 seconds apart from the several first ones, so you'll need to really zoom out (hold S). Click on the first purple one, zoom out, hold Ctrl and click on the last one. Observe the diff.
1.8 MB Download

Comment 33 by, Nov 3 2016

Note: the above (#32) was ran on Android.

Comment 34 by, Nov 4 2016

Components: Internals>Skia
After almost 20 hours SkResourceCache::fHash buffer size grew to 16 MiB.

Comment 35 by, Nov 7 2016

-> reed@ for triage. Seems like it might be a fragmentation issue that keeps growing the cache? From what I recall Skia caches either use discardable memory or they have a hard limit, so I wonder if this will grow some but eventually stop growing. Specifically purgeAsNeeded is called in SkResourceCache::add, which checks some limits and evicts the cache. 

The only place that codesearch seems to find where the non-discardable memory is used is in SkFontMgr, which sets the limit to 32k here:

reed@, do you know if there are other places that use non-discardable SkResourceCache?

Comment 36 by, Nov 7 2016


Comment 37 by, Nov 7 2016

I believe it.  No hash table in Skia ever shrinks its tables.  (They do of course allow elements to be removed.)

I don't think there's any reason we can't have the tables shrink.  If I remember right, it was just a simplification to keep the implementation complexity down.

I'd also like to try getting out of the hash table business altogether, and just try to use std::unordered_map.

Comment 38 by, Dec 12 2016

What is the next step? Should this continue to be Pri-1 for M55?

Comment 39 by, Dec 12 2016

Labels: -Pri-1 Pri-3
I've been looking at updating our hash table code today.

This has been live long enough that I have a hard time believing there's a particular rush for any milestone.

Comment 40 by, Dec 15 2016

Project Member
The following revision refers to this bug:

commit e4bf164225cc6d027566e9bfa0c8492629a6e090
Author: Mike Klein <>
Date: Tue Dec 13 21:26:32 2016

Port SkResourceCache to SkTHashTable

We'd like to fix bugs and make performance improvements to our hash tables.  It's a lot easier if we can focus on one implementation, so I'd like to move users of SkTDynamicHash to SkTHashTable, SkTHashMap, or SkTHashSet.  This is roughly outlined in the attached Skia bug.

In this case, the conversion from SkTDynamicHash to SkTHashTable is pretty trivial.  The main change is that the values stored in the table are no longer assumed to be pointers, so we just need to sprinkle in a couple of * and ->.

SkResourceCache is particularly interesting as the locus of the attached Chromium bug.  Porting this now means SkResourceCache will get any fixes we make as soon as we make them.

BUG= skia:6053 ,chromium:429375

Change-Id: If5dc8d331c62f1d4449fb8f9a7f7e9c746070213
Reviewed-by: Herb Derby <>
Commit-Queue: Mike Klein <>


Comment 41 by, Dec 15 2016

Project Member
The following revision refers to this bug:

commit 6e98a82eb3adcc9a1e9ae20e2d26b6dba24f9652
Author: skia-deps-roller <>
Date: Thu Dec 15 23:37:02 2016

Roll src/third_party/skia/ 344ec42f6..d85dd53e2 (6 commits).

$ git log 344ec42f6..d85dd53e2 --date=short --no-merges --format='%ad %ae %s'
2016-12-15 brianosman Shrink the SkImageGenerator API
2016-12-14 stani Exclude complexclip4 GM tests from tile_rt config
2016-12-15 reed speedup dynamicwstream
2016-12-13 mtklein Port SkResourceCache to SkTHashTable
2016-12-15 reed remove unused dynamicwstream.snapshotAsData()
2016-12-15 kjlubick Update Pixel Cs -> NFM26H


Documentation for the AutoRoller is here:

If the roll is causing failures, see:


Cr-Commit-Position: refs/heads/master@{#438953}


Comment 42 by, Apr 25 2017

Labels: -Performance

Comment 43 Deleted

Comment 44 by, Apr 30 2017


Comment 45 by, Jun 13 2017


Comment 46 by, Sep 20 2017


Sign in to add a comment