找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 53|回复: 1

[原创代码] 一个内存清理的小工具(有定时功能)

[复制链接]
发表于 6 小时前 | 显示全部楼层 |阅读模式
本帖最后由 Nsqs 于 2026-4-25 14:16 编辑
  1. <#
  2. .SYNOPSIS
  3.     Win11 内存净化器(v 1.0.0)
  4. .DESCRIPTION
  5.     适配 PowerShell 5.1 / Win11,提供:
  6.     · 手动模式:三步独立动作
  7.     · 自动模式:循环定时释放
  8.     · 调试模式:通过 -DebugInterval 传入自定义间隔(如 "600"、"1:30"、"1:30:00"),开启调试菜单;使用 -PassThru 无效化调试模式(采用默认值)
  9.     · 自适应单位显示(支持负数,如 -1.32 GB)
  10. #>
  11. #Requires -RunAsAdministrator
  12. param(
  13.     [string]$DebugInterval,
  14.     [switch]$PassThru
  15. )

  16. Clear-Host

  17. # ========== ANSI 色彩 ==========
  18. $esc = [char]0x1b
  19. $reset       = "$esc[0m"
  20. $cyan        = "$esc[36m"
  21. $green       = "$esc[32m"
  22. $yellow      = "$esc[33m"
  23. $gray        = "$esc[90m"
  24. $white       = "$esc[37m"
  25. $red         = "$esc[31m"
  26. $blue        = "$esc[34m"
  27. $brightCyan  = "$esc[96m"

  28. $cLine       = $cyan
  29. $cTitle      = $green
  30. $cStep       = $yellow
  31. $cOK         = $green
  32. $cWarn       = $yellow
  33. $cText       = $white
  34. $cDim        = $gray
  35. $cLabel      = $blue
  36. $cBracket    = $white
  37. $cBracketTxt = $brightCyan
  38. $cTime       = $yellow

  39. # ========== 核心 API 加载 ==========
  40. Add-Type @"
  41. using System;
  42. using System.Runtime.InteropServices;
  43. public static class NativeMethods
  44. {
  45.     [DllImport("kernel32.dll")]
  46.     public static extern bool SetProcessWorkingSetSize(IntPtr hProcess, int dwMinimumWorkingSetSize, int dwMaximumWorkingSetSize);
  47.     [DllImport("ntdll.dll", SetLastError = true)]
  48.     public static extern int NtSetSystemInformation(int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength);
  49.     public const int SystemMemoryListInformation = 0x50;
  50. }
  51. public enum MemoryListCommand : int
  52. {
  53.     MemoryPurgeStandbyList = 4,
  54.     MemoryPurgeLowPriorityStandbyList = 5
  55. }
  56. "@

  57. # ========== 辅助函数 ==========
  58. function Format-MemorySize {
  59.     param([long]$Bytes)
  60.     $abs = [Math]::Abs($Bytes)
  61.     $div = if ($abs -ge 1GB) { 1GB }
  62.            elseif ($abs -ge 1MB) { 1MB }
  63.            elseif ($abs -ge 1KB) { 1KB }
  64.            else { 1 }
  65.     $unit = if ($div -eq 1GB) { "GB" }
  66.             elseif ($div -eq 1MB) { "MB" }
  67.             elseif ($div -eq 1KB) { "KB" }
  68.             else { "Byte" }
  69.     $value = $Bytes / $div
  70.     "{0:N2} {1}" -f $value, $unit
  71. }

  72. function Get-FreeMemoryBytes {
  73.     (Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory * 1024
  74. }

  75. function Compress-WorkingSets {
  76.     Get-Process -ErrorAction SilentlyContinue | ForEach-Object {
  77.         try { [NativeMethods]::SetProcessWorkingSetSize($_.Handle, -1, -1) | Out-Null } catch { }
  78.     }
  79. }
  80. function Clear-StandbyLists {
  81.     $cmd = [MemoryListCommand]::MemoryPurgeStandbyList
  82.     $ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(4)
  83.     [System.Runtime.InteropServices.Marshal]::WriteInt32($ptr, $cmd)
  84.     [NativeMethods]::NtSetSystemInformation([NativeMethods]::SystemMemoryListInformation, $ptr, 4) | Out-Null
  85.     [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr)

  86.     $cmd = [MemoryListCommand]::MemoryPurgeLowPriorityStandbyList
  87.     $ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(4)
  88.     [System.Runtime.InteropServices.Marshal]::WriteInt32($ptr, $cmd)
  89.     [NativeMethods]::NtSetSystemInformation([NativeMethods]::SystemMemoryListInformation, $ptr, 4) | Out-Null
  90.     [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr)
  91. }
  92. function Invoke-DotNetGC {
  93.     [System.GC]::Collect()
  94.     [System.GC]::WaitForPendingFinalizers()
  95.     [System.GC]::Collect()
  96. }

  97. function Clear-MemoryAll {
  98.     Compress-WorkingSets
  99.     Clear-StandbyLists
  100.     Invoke-DotNetGC
  101. }

  102. # ========== 调试模式开关函数 ==========
  103. function Enable-DebugMode {
  104.     param(
  105.         [string]$Interval,
  106.         [switch]$PassThru
  107.     )
  108.     if ($PassThru) {
  109.         Write-Host "调试模式无效化 (PassThru),使用默认常数值" -ForegroundColor Gray
  110.         return
  111.     }

  112.     $seconds = 0
  113.     if ($Interval -match '^(\d+):(\d{1,2}):(\d{1,2})$') {
  114.         $seconds = [int]$Matches[1]*3600 + [int]$Matches[2]*60 + [int]$Matches[3]
  115.     }
  116.     elseif ($Interval -match '^(\d+):(\d{1,2})$') {
  117.         $seconds = [int]$Matches[1]*60 + [int]$Matches[2]
  118.     }
  119.     elseif ($Interval -match '^\d+$') {
  120.         $seconds = [int]$Interval
  121.     }
  122.     else {
  123.         Write-Host "无法解析时间格式,使用默认15秒" -ForegroundColor Yellow
  124.         $seconds = 15
  125.     }
  126.     if ($seconds -le 0) { $seconds = 15 }
  127.     $global:DebugIntervalSeconds = $seconds
  128.     Write-Host "调试模式已激活,自动释放间隔:$seconds 秒" -ForegroundColor Green
  129. }

  130. if ($DebugInterval) {
  131.     Enable-DebugMode -Interval $DebugInterval -PassThru:$PassThru
  132. }

  133. # ========== 手动释放差值记录 ==========
  134. $global:lastManualDelta = $null

  135. # ========== 手动模式步骤 ==========
  136. function Invoke-ManualStep {
  137.     param(
  138.         [string]$InProgressText,
  139.         [string]$CompletedText,
  140.         [scriptblock]$Action
  141.     )
  142.     $line = [System.Console]::CursorTop
  143.     Write-Host $InProgressText
  144.     & $Action
  145.     Start-Sleep -Milliseconds 1500
  146.     [System.Console]::SetCursorPosition(0, $line)
  147.     Write-Host "$CompletedText                    " -NoNewline
  148.     Write-Host ""
  149. }

  150. function ManualRun {
  151.     Clear-Host
  152.     [Console]::CursorVisible = $false

  153.     Write-Host "$cLine┌─────────────────────────────────────┐$reset"
  154.     Write-Host "$cLine│$cTitle        手动释放 - 仪式感模式        $cLine│$reset"
  155.     Write-Host "$cLine└─────────────────────────────────────┘$reset`n"

  156.     $before = Get-FreeMemoryBytes
  157.     Write-Host "  ${cLabel}当前空闲内存  : ${reset}${cText}$(Format-MemorySize $before)$reset`n"

  158.     $procs = @(Get-Process -ErrorAction SilentlyContinue)
  159.     $procCount = $procs.Count
  160.     Invoke-ManualStep `
  161.         "  $cStep⏸️  正在释放进程闲置内存 ${cBracket}(${cBracketTxt}总计 $procCount 个进程${cBracket})$reset" `
  162.         "  $cOK✅ 释放进程闲置内存 完成 ${cBracket}(${cBracketTxt}已处理 $procCount 个进程${cBracket})$reset" `
  163.         { Compress-WorkingSets }

  164.     Invoke-ManualStep `
  165.         "  $cStep⏸️  正在清理系统缓存...$reset" `
  166.         "  $cOK✅ 清理系统缓存 完成$reset" `
  167.         { Clear-StandbyLists }

  168.     Invoke-ManualStep `
  169.         "  $cStep⏸️  正在整理托管内存...$reset" `
  170.         "  $cOK✅ 整理托管内存 完成$reset" `
  171.         { Invoke-DotNetGC }

  172.     $after = Get-FreeMemoryBytes
  173.     $delta = $after - $before

  174.     Write-Host "`n  ${cDim}───────────────────────────────────$reset"
  175.     Write-Host "  ${cLabel}优化后空闲内存 : ${reset}${cText}$(Format-MemorySize $after)$reset"
  176.     if ($delta -gt 0) {
  177.         Write-Host "  ${cLabel}释放量         : ${reset}${green}+$(Format-MemorySize $delta)$reset"
  178.     } else {
  179.         Write-Host "  ${cLabel}释放量         : ${reset}${cDim}内存已处于最佳状态,无需释放$reset"
  180.     }

  181.     if ($null -ne $global:lastManualDelta) {
  182.         $diff = $delta - $global:lastManualDelta
  183.         $diffColor = if ($diff -ge 0) { $green } else { $red }
  184.         $sign = if ($diff -ge 0) { "+" } else { "" }
  185.         Write-Host "  ${cLabel}比上次         : ${reset}${diffColor}$sign$(Format-MemorySize $diff)$reset"
  186.     }
  187.     $global:lastManualDelta = $delta

  188.     Write-Host "  ${cDim}───────────────────────────────────$reset`n"

  189.     [Console]::CursorVisible = $true
  190.     Write-Host "按任意键返回主菜单..."
  191.     cmd /c pause | Out-Null
  192. }

  193. # ========== 自动模式 ==========
  194. $script:lastDelta = 0
  195. $script:nextRunTime = Get-Date

  196. function Show-MarqueCleanup {
  197.     param([scriptblock]$Action)
  198.     $line = [System.Console]::CursorTop
  199.     Write-Host "  $cLine┌──────────────────────────────────┐$reset"
  200.     Write-Host "  $cLine│$cStep  ⏸️ 正在静默释放内存...          │$reset"
  201.     Write-Host "  $cLine└──────────────────────────────────┘$reset"
  202.     $boxEndLine = [System.Console]::CursorTop - 1
  203.     & $Action
  204.     $spin = @('⠋','⠙','⠹','⠸','⠼','⠴','⠦','⠧','⠇','⠏')
  205.     for ($i=0; $i -lt 20; $i++) {
  206.         [System.Console]::SetCursorPosition(0, $boxEndLine - 1)
  207.         Write-Host "  $cLine│$cStep  ⏸️ 正在静默释放内存... $($spin[$i % 10])        $cLine│$reset"
  208.         Start-Sleep -Milliseconds 100
  209.     }
  210.     [System.Console]::SetCursorPosition(0, $boxEndLine - 2)
  211.     Write-Host "  $cLine┌──────────────────────────────────┐$reset"
  212.     Write-Host "  $cLine│$cOK  ✅ 静默释放完成                 $cLine│$reset"
  213.     Write-Host "  $cLine└──────────────────────────────────┘$reset"
  214.     Write-Host ""
  215. }

  216. function Draw-IdleBox {
  217.     param([datetime]$NextRun)
  218.     $timeStr = $NextRun.ToString("yyyy.MM.dd HH:mm")
  219.     Write-Host "$cLine┌─────────────────────────────────────┐$reset"
  220.     Write-Host "$cLine│$cText       计划下次在 ${cTime}$timeStr   $cLine│$reset"
  221.     Write-Host "$cLine│$cText         静默释放内存                $cLine│$reset"
  222.     Write-Host "$cLine└─────────────────────────────────────┘$reset"
  223. }

  224. function AutoRun {
  225.     param([int]$IntervalSeconds)
  226.     Clear-Host
  227.     [Console]::CursorVisible = $false

  228.     Write-Host "$cLine┌─────────────────────────────────────┐$reset"
  229.     Write-Host "$cLine│$cTitle         自动模式(跑马灯)          $cLine│$reset"
  230.     Write-Host "$cLine└─────────────────────────────────────┘$reset`n"

  231.     $before = Get-FreeMemoryBytes
  232.     Show-MarqueCleanup { Clear-MemoryAll }
  233.     $after = Get-FreeMemoryBytes
  234.     $delta = $after - $before
  235.     $script:lastDelta = $delta

  236.     Write-Host "  ${cLabel}本次释放量 : ${reset}${cText}$(Format-MemorySize $delta)$reset"
  237.     Write-Host "  ${cDim}${cBracket}(${cBracketTxt}首次释放,无历史比较${cBracket})$reset`n"
  238.     Start-Sleep -Seconds 1.5

  239.     $script:nextRunTime = (Get-Date).AddSeconds($IntervalSeconds)
  240.     Clear-Host
  241.     [System.Console]::SetCursorPosition(0, 0)
  242.     Draw-IdleBox -NextRun $script:nextRunTime

  243.     while ($true) {
  244.         $waitSeconds = [math]::Max(1, ($script:nextRunTime - (Get-Date)).TotalSeconds)
  245.         Start-Sleep -Seconds ([int]($waitSeconds))
  246.         if ((Get-Date) -ge $script:nextRunTime) {
  247.             Clear-Host
  248.             [System.Console]::SetCursorPosition(0, 0)

  249.             $b = Get-FreeMemoryBytes
  250.             Show-MarqueCleanup { Clear-MemoryAll }
  251.             $a = Get-FreeMemoryBytes
  252.             $d = $a - $b

  253.             Write-Host "  ${cLabel}本次释放量 : ${reset}${cText}$(Format-MemorySize $d)$reset"
  254.             if ($script:lastDelta -ne 0) {
  255.                 $diff = $d - $script:lastDelta
  256.                 $diffColor = if ($diff -ge 0) { $green } else { $red }
  257.                 $sign = if ($diff -ge 0) { "+" } else { "" }
  258.                 Write-Host "  ${cLabel}比上次     : ${reset}${diffColor}$sign$(Format-MemorySize $diff)$reset"
  259.             } else {
  260.                 Write-Host "  ${cDim}${cBracket}(${cBracketTxt}首次释放,无历史比较${cBracket})$reset"
  261.             }
  262.             $script:lastDelta = $d
  263.             $script:nextRunTime = (Get-Date).AddSeconds($IntervalSeconds)

  264.             Start-Sleep -Seconds 2
  265.             Clear-Host
  266.             [System.Console]::SetCursorPosition(0, 0)
  267.             Draw-IdleBox -NextRun $script:nextRunTime
  268.         }
  269.     }
  270. }

  271. # ========== 主菜单 ==========
  272. function Show-MainMenu {
  273.     while ($true) {
  274.         Clear-Host
  275.         Write-Host "$cLine┌─────────────────────────────────────┐$reset"
  276.         Write-Host "$cLine│$cTitle      Win11 内存净化器           $cLine│$reset"
  277.         Write-Host "$cLine└─────────────────────────────────────┘$reset`n"
  278.         Write-Host "  ${cText}1. 手动运行  ${cBracket}(${cBracketTxt}三步仪式感${cBracket})$reset"
  279.         Write-Host "  ${cText}2. 自动运行  ${cBracket}(${cBracketTxt}定时静默释放${cBracket})$reset"
  280.         Write-Host "  ${cText}3. 退出$reset"
  281.         Write-Host ""
  282.         $choice = Read-Host "  请选择 (1/2/3)"

  283.         switch ($choice) {
  284.             '1' { ManualRun }
  285.             '2' {
  286.                 Clear-Host
  287.                 Write-Host "  ${cText}选择自动释放间隔:$reset"
  288.                 Write-Host "  ${cText}1. ${cBracketTxt}30 分钟$reset"
  289.                 Write-Host "  ${cText}2. ${cBracketTxt}1 小时$reset"
  290.                 Write-Host "  ${cText}3. ${cBracketTxt}2 小时$reset"
  291.                 Write-Host "  ${cText}4. ${cBracketTxt}3 小时$reset"
  292.                 Write-Host "  ${cText}5. ${cBracketTxt}5 小时$reset"
  293.                 if ($global:DebugIntervalSeconds -gt 0) {
  294.                     Write-Host "  ${cText}6. ${cDim}测试模式 ${cBracket}(${cBracketTxt}当前间隔: $global:DebugIntervalSeconds 秒${cBracket})$reset"
  295.                 }
  296.                 Write-Host ""
  297.                 $sub = Read-Host "  输入数字"
  298.                 $interval = switch ($sub) {
  299.                     '1' { 30 * 60 }
  300.                     '2' { 60 * 60 }
  301.                     '3' { 120 * 60 }
  302.                     '4' { 180 * 60 }
  303.                     '5' { 300 * 60 }
  304.                     '6' { if ($global:DebugIntervalSeconds -gt 0) { $global:DebugIntervalSeconds } else { Write-Host "无效选项,返回主菜单"; Start-Sleep 1; continue } }
  305.                     default { Write-Host "无效选项,返回主菜单"; Start-Sleep 1; continue }
  306.                 }
  307.                 AutoRun -IntervalSeconds $interval
  308.             }
  309.             '3' {
  310.                 Write-Host "`n  ${cText}已退出,愉快!$reset`n"
  311.                 exit
  312.             }
  313.             default {
  314.                 Write-Host "  ${cWarn}无效选项,请重新输入$reset"
  315.                 Start-Sleep 1
  316.             }
  317.         }
  318.     }
  319. }

  320. <# ========== 入口 ==========
  321. 调试模式函数参数方法:
  322.    Enable-DebugMode -Interval 600
  323.    Enable-DebugMode -Interval 00:00:05
  324.    Enable-DebugMode -Interval 1:30 -PassThru # Pass 用于采用默认模式
  325. #>
  326. Show-MainMenu
复制代码
发表于 6 分钟前 | 显示全部楼层
这个好,正需要
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-4-25 20:37

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表