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

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()
_ = 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 {
//
//
_ = 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 "稳定"
}
}
}