|
|
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 "稳定"
|
|
|
}
|
|
|
}
|
|
|
}
|