6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rust で Google Chrome のメモリ使用量を減らす

Last updated at Posted at 2020-04-18

動機

こんなポンコツ PC でプログラミングしています。VSCode とブラウザ開いただけでこの有様だよ!
クリップボード一時ファイル01.png
VSCode にはメモリを一杯使ってサクサク動いて欲しいので、「Chrome オメーに喰わせるメモリはねぇ!」ということを実践してみたいと思います。Rust で。(いつもは Firefox 使ってますが、Chrome の方が受けがいいかなと思って Chrome にしてます)

結果

先に結果です。

↓減らす前
クリップボード一時ファイル04.png
↓減らした後
クリップボード一時ファイル03.png
わーい、Chrome のメモリ使用量減ったー。

どうやるか

EmptyWorkingSet 関数を呼んでるだけです。おわり。

解説

ワーキングセットとは?

ワーキングセットとは、物理メモリー領域の中でも、アプリケーションが現在使用している状態の領域のことである。言い換えれば、アプリケーションが使用しているメモリーでもあまり使用されていないデータをOSがハードディスクに退避(スワップ)させる際に、退避の対象とならずに物理メモリー内に留められる部分のこと。

なのでワーキングセットを空にすることはアプリケーションのパフォーマンスに重大な影響を及ぼします。HDD のころはEmptyWorkingSet関数を呼ぶと、カリカリ言って実用に耐えないレベルでした。最近の比較的高速なストレージならあまり気にならないかもしれません。

コード

ここでの肝は main.rs の中のimpl Drop for Handleです。Dropを実装した Rust の構造体にHANDLEを束縛することで、スコープを抜けたら自動的にリソースを開放するようにしています。

Cargo.toml
[package]
name = "chromempty"
version = "0.1.0"
authors = ["benki"]
edition = "2018"

[dependencies.winapi]
version = "0.3"
features = ["tlhelp32", "handleapi", "processthreadsapi", "psapi"]
main.rs
use std::ffi::CStr;
use std::mem;
use std::os::raw::c_char;
use std::thread;
use std::time::Duration;
use winapi::{
    shared::minwindef::{FALSE, TRUE},
    um::{
        handleapi::{CloseHandle, INVALID_HANDLE_VALUE},
        processthreadsapi::OpenProcess,
        psapi::EmptyWorkingSet,
        tlhelp32::{
            CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32,
            TH32CS_SNAPPROCESS,
        },
        winnt::{HANDLE, PROCESS_ALL_ACCESS},
    },
};

struct Handle(HANDLE);

impl Drop for Handle {
    fn drop(&mut self) {
        unsafe { CloseHandle(self.0); }
    }
}

fn main() {
    loop {
        chromempty();
        thread::sleep(Duration::from_secs(5));
    }
}

fn chromempty() {
    unsafe {
        let mut entry = mem::MaybeUninit::<PROCESSENTRY32>::uninit().assume_init();
        entry.dwSize = mem::size_of::<PROCESSENTRY32>() as u32;

        let snap_shot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if snap_shot == INVALID_HANDLE_VALUE {
            return;
        }
        // SNAPSHOT HANDLE を Rust の構造体に束縛
        let snap_shot = Handle(snap_shot);

        if Process32First(snap_shot.0, &mut entry) == TRUE {
            while Process32Next(snap_shot.0, &mut entry) == TRUE {
                if let Ok(exe) = CStr::from_ptr(&entry.szExeFile as *const c_char).to_str() {
                    if exe.eq("chrome.exe") {
                        let handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
                        if handle.is_null() {
                            continue;
                        }
                        // PROCESS HANDLE を束縛
                        let handle = Handle(handle);
                        EmptyWorkingSet(handle.0);
                        // PROCESS HANDLE はここで開放される
                    }
                }
            }
        }
        // SNAPSHOT HANDLE はここで開放される
    }
}

まとめ

  • EmptyWorkingSet関数を知ったよ
  • ワーキングセットとは何かを知ったよ
  • Dropによる自動的なリソース開放を知ったよ
  • ポンコツ PC つらい:sob:
6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?