You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

563 lines
18 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import Foundation
import UIKit
import Combine
// MARK: -
enum MemoryPressureLevel: CaseIterable {
case normal
case moderate
case high
case critical
case extreme
var description: String {
switch self {
case .normal:
return "正常"
case .moderate:
return "中等"
case .high:
return ""
case .critical:
return "严重"
case .extreme:
return "极端"
}
}
}
// MARK: - 使
struct SystemMemoryUsage {
let freeMB: Double
let activeMB: Double
let inactiveMB: Double
let wiredMB: Double
}
// MARK: -
struct DetailedMemoryInfo {
let residentMemoryMB: Double
let virtualMemoryMB: Double
let physicalMemoryMB: Double
let memoryPressure: MemoryPressureLevel
let availableMemoryMB: Double
let systemMemoryUsage: SystemMemoryUsage
let timestamp: Date
}
// MARK: -
class MemoryMonitor: ObservableObject {
static let shared = MemoryMonitor()
@Published var currentMemoryUsage: String = "Unknown"
@Published var memoryWarningCount: Int = 0
private var memoryCheckTimer: Timer?
init() {
//
NotificationCenter.default.addObserver(
self,
selector: #selector(handleMemoryWarning),
name: UIApplication.didReceiveMemoryWarningNotification,
object: nil
)
//
startMemoryMonitoring()
}
deinit {
NotificationCenter.default.removeObserver(self)
stopMemoryMonitoring()
}
// MARK: - 使
/// 使
func getMemoryUsage() -> String {
let usedMB = getMemoryUsageInMB()
return String(format: "%.1f MB", usedMB)
}
/// 使MB
func getMemoryUsageInMB() -> Double {
// 使
let stats = getAccurateMemoryStats()
return stats.residentMemoryMB
}
///
private func getAccurateMemoryStats() -> (residentMemoryMB: Double, virtualMemoryMB: Double, physicalMemoryMB: Double) {
var info = mach_task_basic_info()
var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size / MemoryLayout<integer_t>.size)
let kerr: kern_return_t = withUnsafeMutablePointer(to: &info) {
$0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
task_info(mach_task_self_,
task_flavor_t(MACH_TASK_BASIC_INFO),
$0,
&count)
}
}
if kerr == KERN_SUCCESS {
let residentMB = Double(info.resident_size) / 1024.0 / 1024.0
let virtualMB = Double(info.virtual_size) / 1024.0 / 1024.0
let physicalMB = Double(ProcessInfo.processInfo.physicalMemory) / 1024.0 / 1024.0
return (residentMB, virtualMB, physicalMB)
} else {
// mach 使
return getFallbackMemoryStats()
}
}
///
private func getFallbackMemoryStats() -> (residentMemoryMB: Double, virtualMemoryMB: Double, physicalMemoryMB: Double) {
// 使 NSProcessInfo
let processInfo = ProcessInfo.processInfo
let physicalMemory = Double(processInfo.physicalMemory) / 1024.0 / 1024.0
// 使
let estimatedUsage = physicalMemory * 0.1 // 使10%
return (estimatedUsage, estimatedUsage * 2, physicalMemory)
}
/// 使
func getMemoryUsageDetails() -> (usedMB: Double, totalMB: Double, percentage: Double) {
let stats = getAccurateMemoryStats()
let usedMB = stats.residentMemoryMB
let totalMB = stats.physicalMemoryMB
let percentage = totalMB > 0 ? (usedMB / totalMB) * 100.0 : 0.0
return (usedMB, totalMB, percentage)
}
///
func getDetailedMemoryInfo() -> DetailedMemoryInfo {
let stats = getAccurateMemoryStats()
let processInfo = ProcessInfo.processInfo
return DetailedMemoryInfo(
residentMemoryMB: stats.residentMemoryMB,
virtualMemoryMB: stats.virtualMemoryMB,
physicalMemoryMB: stats.physicalMemoryMB,
memoryPressure: getMemoryPressureLevel(),
availableMemoryMB: getAvailableMemoryMB(),
systemMemoryUsage: getSystemMemoryUsage(),
timestamp: Date()
)
}
///
private func getAvailableMemoryMB() -> Double {
// 使 ProcessInfo
let processInfo = ProcessInfo.processInfo
let physicalMemory = Double(processInfo.physicalMemory) / 1024.0 / 1024.0
//
//
let estimatedAvailable = physicalMemory * 0.3 // 30%
return estimatedAvailable
}
/// 使
private func getSystemMemoryUsage() -> SystemMemoryUsage {
var stats = vm_statistics64()
var count = mach_msg_type_number_t(MemoryLayout<vm_statistics64>.size / MemoryLayout<integer_t>.size)
let result = withUnsafeMutablePointer(to: &stats) {
$0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
host_statistics64(mach_host_self(),
HOST_VM_INFO64,
$0,
&count)
}
}
if result == KERN_SUCCESS {
let pageSize = vm_kernel_page_size
let freeMB = Double(stats.free_count) * Double(pageSize) / 1024.0 / 1024.0
let activeMB = Double(stats.active_count) * Double(pageSize) / 1024.0 / 1024.0
let inactiveMB = Double(stats.inactive_count) * Double(pageSize) / 1024.0 / 1024.0
let wiredMB = Double(stats.wire_count) * Double(pageSize) / 1024.0 / 1024.0
return SystemMemoryUsage(
freeMB: freeMB,
activeMB: activeMB,
inactiveMB: inactiveMB,
wiredMB: wiredMB
)
}
return SystemMemoryUsage(freeMB: 0, activeMB: 0, inactiveMB: 0, wiredMB: 0)
}
///
private func getMemoryPressureLevel() -> MemoryPressureLevel {
let stats = getAccurateMemoryStats()
let percentage = stats.physicalMemoryMB > 0 ? (stats.residentMemoryMB / stats.physicalMemoryMB) * 100.0 : 0.0
switch percentage {
case 0..<50:
return .normal
case 50..<70:
return .moderate
case 70..<85:
return .high
case 85..<95:
return .critical
default:
return .extreme
}
}
// MARK: -
///
func checkMemoryPressure() {
let memoryUsage = getMemoryUsage()
currentMemoryUsage = memoryUsage
print("📊 当前内存使用: \(memoryUsage)")
let detailedInfo = getDetailedMemoryInfo()
print("📊 内存压力等级: \(detailedInfo.memoryPressure.description)")
//
switch detailedInfo.memoryPressure {
case .high, .critical, .extreme:
print("⚠️ 内存压力较高,执行清理操作")
performMemoryCleanup()
case .moderate:
print("⚠️ 内存压力中等,建议清理")
suggestMemoryCleanup()
case .normal:
print("✅ 内存使用正常")
}
}
///
func performMemoryCleanup() {
print("🧹 执行内存清理操作")
//
ImageCacheManager.shared.clearCache()
//
cleanupTempFiles()
//
NotificationCenter.default.post(name: .memoryCleanup, object: nil)
//
autoreleasepool {
//
}
}
///
func suggestMemoryCleanup() {
print("💡 建议执行内存清理")
//
ImageCacheManager.shared.clearCache()
//
NotificationCenter.default.post(name: .memoryCleanupSuggestion, object: nil)
}
// MARK: -
///
private func cleanupTempFiles() {
let tempPath = NSTemporaryDirectory()
let fileManager = FileManager.default
do {
let tempFiles = try fileManager.contentsOfDirectory(atPath: tempPath)
var cleanedCount = 0
for file in tempFiles {
let filePath = (tempPath as NSString).appendingPathComponent(file)
//
if file.hasSuffix(".jpg") || file.hasSuffix(".png") || file.hasSuffix(".tmp") {
try fileManager.removeItem(atPath: filePath)
cleanedCount += 1
}
}
print("🗑️ 清理了 \(cleanedCount) 个临时文件")
} catch {
print("❌ 清理临时文件失败: \(error)")
}
}
// MARK: -
///
func startMemoryMonitoring() {
stopMemoryMonitoring() //
// 30使
memoryCheckTimer = Timer.scheduledTimer(withTimeInterval: 30.0, repeats: true) { [weak self] _ in
self?.checkMemoryPressure()
}
print("📊 内存监控已启动")
}
///
func stopMemoryMonitoring() {
memoryCheckTimer?.invalidate()
memoryCheckTimer = nil
print("📊 内存监控已停止")
}
// MARK: -
@objc private func handleMemoryWarning() {
memoryWarningCount += 1
print("🚨 收到内存警告 #\(memoryWarningCount)")
//
performMemoryCleanup()
//
NotificationCenter.default.post(name: .memoryWarning, object: nil)
}
// MARK: -
///
func getMemoryStatistics() -> MemoryStatistics {
let details = getMemoryUsageDetails()
return MemoryStatistics(
usedMB: details.usedMB,
totalMB: details.totalMB,
percentage: details.percentage,
warningCount: memoryWarningCount,
timestamp: Date()
)
}
///
func printMemoryStatistics() {
let stats = getMemoryStatistics()
print("📊 内存统计信息:")
print(" - 已使用: \(String(format: "%.1f MB", stats.usedMB))")
print(" - 总内存: \(String(format: "%.1f MB", stats.totalMB))")
print(" - 使用率: \(String(format: "%.1f%%", stats.percentage))")
print(" - 警告次数: \(stats.warningCount)")
print(" - 检查时间: \(stats.timestamp)")
}
}
// MARK: -
struct MemoryStatistics {
let usedMB: Double
let totalMB: Double
let percentage: Double
let warningCount: Int
let timestamp: Date
}
// MARK: -
extension Notification.Name {
static let memoryWarning = Notification.Name("memoryWarning")
static let memoryCleanup = Notification.Name("memoryCleanup")
static let memoryCleanupSuggestion = Notification.Name("memoryCleanupSuggestion")
}
// MARK: -
extension MemoryMonitor {
///
func shouldOptimizeMemory() -> Bool {
let details = getMemoryUsageDetails()
return details.percentage > 70.0 || details.usedMB > 200.0
}
///
func getMemoryOptimizationSuggestions() -> [String] {
var suggestions: [String] = []
let details = getMemoryUsageDetails()
if details.percentage > 80.0 {
suggestions.append("内存使用率过高,建议关闭其他应用")
}
if details.usedMB > 250.0 {
suggestions.append("内存使用量过大,建议重启应用")
}
if memoryWarningCount > 3 {
suggestions.append("频繁收到内存警告,建议检查内存泄漏")
}
if suggestions.isEmpty {
suggestions.append("内存使用正常")
}
return suggestions
}
///
func performDeepMemoryCleanup() {
print("🧹 执行深度内存清理")
// 1.
ImageCacheManager.shared.clearCache()
// 2.
cleanupTempFiles()
// 3.
URLCache.shared.removeAllCachedResponses()
// 4.
NotificationCenter.default.post(name: .deepMemoryCleanup, object: nil)
// 5.
autoreleasepool {
//
let _ = Array(0..<1000).map { _ in String(repeating: "x", count: 1000) }
}
print("✅ 深度内存清理完成")
}
}
// MARK: -
extension Notification.Name {
static let deepMemoryCleanup = Notification.Name("deepMemoryCleanup")
}
// MARK: -
extension MemoryMonitor {
///
func getSystemMemoryInfo() -> SystemMemoryInfo {
let processInfo = ProcessInfo.processInfo
let physicalMemory = Double(processInfo.physicalMemory) / 1024.0 / 1024.0
// 使
let appMemory = getMemoryUsageInMB()
// 使
let systemMemory = physicalMemory - appMemory
return SystemMemoryInfo(
totalPhysicalMemoryMB: physicalMemory,
appMemoryMB: appMemory,
systemMemoryMB: max(0, systemMemory),
availableMemoryMB: getAvailableMemoryMB(),
memoryPressure: getMemoryPressureLevel()
)
}
///
func checkMemoryLeak() -> MemoryLeakReport {
let currentMemory = getMemoryUsageInMB()
// 使
let report = MemoryLeakReport(
currentMemoryMB: currentMemory,
memoryGrowth: 0, //
potentialLeak: currentMemory > 300, // 300MB
recommendation: currentMemory > 300 ? "内存使用过高,可能存在内存泄漏" : "内存使用正常"
)
return report
}
///
func optimizeMonitoringFrequency() {
let memoryPressure = getMemoryPressureLevel()
switch memoryPressure {
case .normal:
// 60
updateMonitoringInterval(60.0)
case .moderate:
// 30
updateMonitoringInterval(30.0)
case .high:
// 15
updateMonitoringInterval(15.0)
case .critical, .extreme:
// 5
updateMonitoringInterval(5.0)
}
}
///
private func updateMonitoringInterval(_ interval: TimeInterval) {
stopMemoryMonitoring()
memoryCheckTimer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { [weak self] _ in
self?.checkMemoryPressure()
}
print("📊 内存监控间隔已更新为 \(interval)")
}
/// 使
func getMemoryTrend() -> MemoryTrend {
//
//
let currentMemory = getMemoryUsageInMB()
let pressure = getMemoryPressureLevel()
return MemoryTrend(
currentLevel: pressure,
trend: .stable, //
recommendation: getMemoryOptimizationSuggestions().first ?? "内存使用正常"
)
}
}
// MARK: -
struct SystemMemoryInfo {
let totalPhysicalMemoryMB: Double
let appMemoryMB: Double
let systemMemoryMB: Double
let availableMemoryMB: Double
let memoryPressure: MemoryPressureLevel
}
struct MemoryLeakReport {
let currentMemoryMB: Double
let memoryGrowth: Double
let potentialLeak: Bool
let recommendation: String
}
struct MemoryTrend {
let currentLevel: MemoryPressureLevel
let trend: MemoryTrendDirection
let recommendation: String
}
enum MemoryTrendDirection {
case increasing
case decreasing
case stable
var description: String {
switch self {
case .increasing:
return "上升"
case .decreasing:
return "下降"
case .stable:
return "稳定"
}
}
}