While investigating an apparent IOSurface leak in my app, which makes heavy use of WKWebViews, I found that if I simply create an empty web view and start changing page zoom by pinching, I can see the number of IOSurfaces steadily increasing. Programmatically changing the zoom also has this effect. The controller below gets to 3.58GB of persistent IOSurface objects in about 20 seconds. This behavior continues indefinitely. Is this a leak?
I don't think this is just related to zooming, tapping and scrolling also seem to leak IOSurfaces. The problem I was investigating occurs without any of this, just dynamically modifying a web page containing svgs, but I wonder if this is somehow related, as the allocation stack traces are all the same.
I'm running on iOS 18.1.1 on an iPad Pro 12.9in 4th gen.
class LeakTestController: UIViewController {
private(set) var webView: WKWebView!
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
nil
}
override func viewDidLoad() {
let config = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: config)
view.addSubview(webView)
webView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
view.topAnchor.constraint(equalTo: webView.topAnchor),
view.bottomAnchor.constraint(equalTo: webView.bottomAnchor),
view.leadingAnchor.constraint(equalTo: webView.leadingAnchor),
view.trailingAnchor.constraint(equalTo: webView.trailingAnchor)
])
webView.loadHTMLString("hi", baseURL: nil)
startZooming()
}
func startZooming() {
Task.init {
while true {
try await Task.sleep(nanoseconds: 1000000)
webView.pageZoom = 0.5
try await Task.sleep(nanoseconds: 1000000)
webView.pageZoom = 1
}
}
}
}
The stack trace for the allocations is:
IOSurfaceClientLookupFromMachPort
-[IOSurface initWithMachPort:]
WebCore::IOSurface::createFromSendRight(WTF::MachSendRight const&&)
decltype(auto) std::__1::__variant_detail::__visitation::__base::__dispatcher<1ul>::__dispatch[abi:sn180100]<std::__1::__variant_detail::__visitation::__variant::__value_visitor<WTF::Visitor<WebKit::RemoteLayerBackingStoreProperties::layerContentsBufferFromBackendHandle(std::__1::variant<WebCore::ShareableBitmapHandle, WTF::MachSendRight>&&, WebKit::LayerContentsType)::$_0, WebKit::RemoteLayerBackingStoreProperties::layerContentsBufferFromBackendHandle(std::__1::variant<WebCore::ShareableBitmapHandle, WTF::MachSendRight>&&, WebKit::LayerContentsType)::$_1>>&&, std::__1::__variant_detail::__base<(std::__1::__variant_detail::_Trait)1, WebCore::ShareableBitmapHandle, WTF::MachSendRight>&>(std::__1::__variant_detail::__visitation::__variant::__value_visitor<WTF::Visitor<WebKit::RemoteLayerBackingStoreProperties::layerContentsBufferFromBackendHandle(std::__1::variant<WebCore::ShareableBitmapHandle, WTF::MachSendRight>&&, WebKit::LayerContentsType)::$_0, WebKit::RemoteLayerBackingStoreProperties::layerContentsBufferFromBackendHandle(std::__1::variant<WebCore::ShareableBitmapHandle, WTF::MachSendRight>&&, WebKit::LayerContentsType)::$_1>>&&, std::__1::__variant_detail::__base<(std::__1::__variant_detail::_Trait)1, WebCore::ShareableBitmapHandle, WTF::MachSendRight>&)
WebKit::RemoteLayerBackingStoreProperties::layerContentsBufferFromBackendHandle(std::__1::variant<WebCore::ShareableBitmapHandle, WTF::MachSendRight>&&, WebKit::LayerContentsType)
WebKit::RemoteLayerTreePropertyApplier::applyPropertiesToLayer(CALayer*, WebKit::RemoteLayerTreeNode*, WebKit::RemoteLayerTreeHost*, WebKit::LayerProperties const&, WebKit::LayerContentsType)
WebKit::RemoteLayerTreePropertyApplier::applyProperties(WebKit::RemoteLayerTreeNode&, WebKit::RemoteLayerTreeHost*, WebKit::LayerProperties const&, WTF::HashMap<WebCore::ProcessQualified<WTF::ObjectIdentifierGeneric<WebCore::PlatformLayerIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>>, std::__1::unique_ptr<WebKit::RemoteLayerTreeNode, std::__1::default_delete<WebKit::RemoteLayerTreeNode>>, WTF::DefaultHash<WebCore::ProcessQualified<WTF::ObjectIdentifierGeneric<WebCore::PlatformLayerIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>>>, WTF::HashTraits<WebCore::ProcessQualified<WTF::ObjectIdentifierGeneric<WebCore::PlatformLayerIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>>>, WTF::HashTraits<std::__1::unique_ptr<WebKit::RemoteLayerTreeNode, std::__1::default_delete<WebKit::RemoteLayerTreeNode>>>, WTF::HashTableTraits> const&, WebKit::LayerContentsType)
WebKit::RemoteLayerTreeHost::updateLayerTree(IPC::Connection const&, WebKit::RemoteLayerTreeTransaction const&, float)
WebKit::RemoteLayerTreeDrawingAreaProxy::commitLayerTree(IPC::Connection&, WTF::Vector<std::__1::pair<WebKit::RemoteLayerTreeTransaction, WebKit::RemoteScrollingCoordinatorTransaction>, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WTF::HashMap<WTF::ObjectIdentifierGeneric<WebKit::RemoteImageBufferSetIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>, std::__1::unique_ptr<WebKit::BufferSetBackendHandle, std::__1::default_delete<WebKit::BufferSetBackendHandle>>, WTF::DefaultHash<WTF::ObjectIdentifierGeneric<WebKit::RemoteImageBufferSetIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>>, WTF::HashTraits<WTF::ObjectIdentifierGeneric<WebKit::RemoteImageBufferSetIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>>, WTF::HashTraits<std::__1::unique_ptr<WebKit::BufferSetBackendHandle, std::__1::default_delete<WebKit::BufferSetBackendHandle>>>, WTF::HashTableTraits>&&)
WebKit::RemoteLayerTreeDrawingAreaProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&)
IPC::MessageReceiverMap::dispatchMessage(IPC::Connection&, IPC::Decoder&)
WebKit::WebProcessProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&)
IPC::Connection::dispatchMessage(WTF::UniqueRef<IPC::Decoder>)
IPC::Connection::dispatchIncomingMessages()
WTF::RunLoop::performWork()
WTF::RunLoop::performWork(void*)
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
__CFRunLoopDoSource0
__CFRunLoopDoSources0
__CFRunLoopRun
CFRunLoopRunSpecific
GSEventRunModal
-[UIApplication _run]
UIApplicationMain
0x192173f40
static UIApplicationDelegate.main()
static AppDelegate.$main()
__debug_main_executable_dylib_entry_point
start
Our engineering teams need to investigate this issue, as resolution may involve changes to Apple's software. Please file a bug report, include a small Xcode project with some directions for reproducing the problem, and post the FB number here once you do.
Bug Reporting: How and Why? has tips on creating your bug report.