[webkit-changes] [WebKit/WebKit] 177d68: Regression: NetworkDataTask's ThreadSafeWeakPtrCon...

Chris Dumez noreply at github.com
Fri Aug 4 11:41:50 PDT 2023


  Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 177d6881d88dfc4e1306156c513b7e9c81d41710
      https://github.com/WebKit/WebKit/commit/177d6881d88dfc4e1306156c513b7e9c81d41710
  Author: Chris Dumez <cdumez at apple.com>
  Date:   2023-08-04 (Fri, 04 Aug 2023)

  Changed paths:
    M Source/WTF/wtf/ThreadSafeWeakHashSet.h
    M Source/WTF/wtf/WeakHashMap.h
    M Source/WTF/wtf/WeakHashSet.h
    M Source/WTF/wtf/WeakListHashSet.h
    M Source/WebKit/NetworkProcess/NetworkDataTask.cpp
    M Source/WebKit/NetworkProcess/NetworkDataTaskBlob.cpp
    M Source/WebKit/NetworkProcess/NetworkDataTaskDataURL.cpp
    M Source/WebKit/NetworkProcess/NetworkSession.cpp
    M Source/WebKit/NetworkProcess/NetworkSession.h
    M Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
    M Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp
    M Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp
    M Tools/TestWebKitAPI/Tests/WTF/WeakPtr.cpp

  Log Message:
  -----------
  Regression: NetworkDataTask's ThreadSafeWeakPtrControlBlock are leaking
https://bugs.webkit.org/show_bug.cgi?id=259808
rdar://112162921

Reviewed by Alex Christensen.

The NetworkProcess memory was growing unboundedly during long-running browsing
benchmarks, which the number of NetworkDataTask's ThreadSafeWeakPtrControlBlock
objects growing very large.

The issue was with the `ThreadSafeWeakHashSet<NetworkDataTask> m_dataTaskSet`
container on the NetworkSession. We would add NetworkDataTask objects to this
WeakHashSet and never explicitly remove them. We had a comment in the code
indicating that the ThreadSafeWeakHashSet's amortized clean up would take care
of removing them. The issue though is that amortized clean up would never happen
and m_dataTaskSet's internal Set would just grow unboundedly, keeping control
blocks alive.

The reason amortized clean up never triggered is that we only add to m_dataTaskSet,
we never remove from it, never clear it and we only very rarely call forEach() on
it. As a result, ThreadSafeWeakHashSet::m_operationCountSinceLastCleanup would only
increment due to the add() calls. The condition for amortized clean up was:
`++m_operationCountSinceLastCleanup / 2 > m_set.size()`.

Since m_operationCountSinceLastCleanup would only increase due to the add() calls
and since nothing would ever get removed from the set, `m_operationCountSinceLastCleanup / 2`
could never reach the size of the set.

I am making several fixes in this patch:
1. I added a `|| m_operationCountSinceLastCleanup > m_maxOperationCountWithoutCleanup`
   check to amortized clean up to guarantee that amortized clean up eventually happens
   and that such weak containers can never grow unboundedly, no matter how they are used.
   m_maxOperationCountWithoutCleanup gets multiplied by 2 whenever the clean up finds
   nothing for proper amortization.
2. I made it so that NetworkDataTask objects remove themselves from the ThreadSafeWeakHashSet
   in their destructor. This is good practice no matter what and makes such the set stays
   small.
3. I actually found a bug in `ThreadSafeWeakHashSet::remove()` when implementing the fix in
   (2). ThreadSafeWeakHashSet::remove() would fail to remove the object from the set if the
   call if made after the object destructor has started running! The reason for this is that
   the ThreadSafeWeakHashSet was using a `std::pair<ControlBlockRefPtr, const T*>` as set
   key internally. This means that we needed to create a ControlBlockRefPtr of the object's
   control block in remove() in order to remove the object from the map. However, 265344 at main
   made it so that ref'ing a control block returns nullptr after the object has started
   destruction. As a result, the first item in the key pair would be nullptr and we'd fail
   to remove. To address the issue, I am dropping the ControlBlockRefPtr from the key and
   using a `HashMap<const T*, ControlBlockRefPtr>` instead of a HashSet.

* Source/WTF/wtf/ThreadSafeWeakHashSet.h:
* Source/WTF/wtf/WeakHashMap.h:
* Source/WTF/wtf/WeakHashSet.h:
* Source/WTF/wtf/WeakListHashSet.h:
* Source/WebKit/NetworkProcess/NetworkDataTask.cpp:
(WebKit::NetworkDataTask::~NetworkDataTask):
* Source/WebKit/NetworkProcess/NetworkSession.cpp:
(WebKit::NetworkSession::registerNetworkDataTask):
(WebKit::NetworkSession::unregisterNetworkDataTask):
* Source/WebKit/NetworkProcess/NetworkSession.h:
* Tools/TestWebKitAPI/Tests/WTF/WeakPtr.cpp:
(TestWebKitAPI::ObjectAddingAndRemovingItself::create):
(TestWebKitAPI::ObjectAddingAndRemovingItself::~ObjectAddingAndRemovingItself):
(TestWebKitAPI::ObjectAddingAndRemovingItself::ObjectAddingAndRemovingItself):
(TestWebKitAPI::TEST):
(TestWebKitAPI::ObjectAddingItselfOnly::create):
(TestWebKitAPI::ObjectAddingItselfOnly::ObjectAddingItselfOnly):

Canonical link: https://commits.webkit.org/266594@main




More information about the webkit-changes mailing list