WKWebView触发内存警告致APP终止,如何清理内存避免崩溃?
解决iOS9下WKWebView内存过高导致APP崩溃的问题
我碰到过类似的iOS9环境下WKWebView内存飙升的问题,结合你的描述和代码,帮你梳理下问题根源和可行的解决方案:
为什么你之前的方法没起作用?
- 你尝试的缓存清理(
URLCache和WKWebsiteDataStore)只能清理网页缓存资源,但内存占用飙升的核心原因是WKWebView的独立内容进程中累积了网页的DOM、JS对象、未释放的页面资源(比如视频、iframe),这些内存不在主进程,缓存清理无法直接回收这部分内存。 webViewWebContentProcessDidTerminate没被调用,是因为系统内存不足时直接终止了整个APP进程,而非单独终止Web内容进程——只有当Web内容进程自身崩溃(比如JS错误、局部内存溢出)时,这个代理方法才会触发。
有效的解决方案
1. 主动销毁并重建WKWebView(最直接有效)
既然Web内容进程的内存无法通过缓存清理回收,最直接的方式是在收到内存警告时销毁当前WKWebView实例,彻底释放其对应的内容进程内存,之后再重建WebView加载页面:
修改你的代码如下:
import UIKit import WebKit class MyAwsomeWebViewController: UIViewController, WKNavigationDelegate { var page: WKWebView? @IBOutlet weak var WKBaseView: UIView! override func viewDidLoad() { super.viewDidLoad() recreateWebView() } // 封装WebView创建逻辑 private func recreateWebView() { let config = WKWebViewConfiguration() // 为每个新WebView创建独立的进程池,避免共享内存累积 config.processPool = WKProcessPool() page = WKWebView(frame: WKBaseView.bounds, configuration: config) guard let webView = page else { return } webView.navigationDelegate = self WKBaseView.addSubview(webView) // 添加约束确保WebView适配父视图 webView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ webView.topAnchor.constraint(equalTo: WKBaseView.topAnchor), webView.leadingAnchor.constraint(equalTo: WKBaseView.leadingAnchor), webView.trailingAnchor.constraint(equalTo: WKBaseView.trailingAnchor), webView.bottomAnchor.constraint(equalTo: WKBaseView.bottomAnchor) ]) // 加载初始页面 if let url = URL(string: "https://hitta.se") { webView.load(URLRequest(url: url)) } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() print("**** MEMORY WARNING! ****") // 1. 销毁当前WebView page?.stopLoading() page?.navigationDelegate = nil page?.removeFromSuperview() page = nil // 2. 清理缓存 URLCache.shared.removeAllCachedResponses() URLCache.shared.diskCapacity = 0 URLCache.shared.memoryCapacity = 0 // 3. 清理WKWebView相关数据 DispatchQueue.main.async { let dataStore = WKWebsiteDataStore.default() dataStore.fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { records in dataStore.removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), for: records, completionHandler: { print("All WKWebsiteData cleaned") }) } } // 4. 重建WebView(如果需要立即恢复页面) recreateWebView() } func webViewWebContentProcessDidTerminate(_ webView: WKWebView) { print("*** Terminate WebView Process ***") // 如果Web内容进程主动崩溃,也可以在这里重建WebView recreateWebView() } }
2. 优化页面导航的内存管理
- 在页面跳转前(比如
webView(_:didStartProvisionalNavigation:)),如果是自研网页,可以让网页执行清理逻辑:func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { // 让网页清理全局变量、定时器等资源 webView.evaluateJavaScript("window.clearAllTimers(); window.clearGlobalVars();") { _, error in if let error = error { print("JS清理失败: \(error)") } } } - 对于第三方网页,可以在离开页面时调用
webView.stopLoading(),避免后台加载不必要的资源。
3. 避免共享WKProcessPool
如果你的APP中有多个WKWebView,不要共享同一个WKProcessPool实例——共享进程池会让多个Web页面运行在同一个内容进程中,内存会持续累积。为每个WebView创建独立的WKProcessPool,可以让系统更灵活地回收单个内容进程的内存。
额外注意事项
- iOS9的WKWebView存在一些已知的内存泄漏问题(比如JS交互时的循环引用),检查你的代码中是否存在
WKScriptMessageHandler未正确移除、或者闭包持有WebView的情况。 - 复杂页面(比如包含视频、大量图片)本身内存占用较高,建议在用户离开页面时主动销毁WebView,而不是等到内存警告触发。
内容的提问来源于stack exchange,提问作者Martin Claesson
相关产品推荐
相关产品推荐

