2016/06/25

VirtualBoxでメモリの動的確保っぽいことをする(修正)

きっかけ


試してみたところうまく行ったのでメモを残します。
環境はホストOS:Linux (Centos 7)、ゲストOS:Windows (Windows 10)です。この組み合わせ以外ではできないと思います。

仕組み


  • ホストのcentos7にpagefile.sys専用の仮想HDDを作成し、RAMディスクのtmpfsに置く。
  • pagefile.sysと仮想HDDは可変サイズに設定しておき、必要に応じてファイルサイズが増えるようにする。
  • pagefile.sysのサイズが増えたらゲストOS再起動で仮想HDDを初期化し、サイズを減らす。

確認

はじめに、ホストのCentos7でtmpfsがどこにマウントされているかdfコマンドで調べる。私の環境では複数箇所にマウントされているので今回は/tmpを使います。

$ df -h
ファイルシス   サイズ  使用  残り 使用% マウント位置
/dev/md125        79G   15G   64G   19% /
devtmpfs         1.7G     0  1.7G    0% /dev
tmpfs            1.8G  476K  1.8G    1% /dev/shm
tmpfs            1.8G  164M  1.6G   10% /run
tmpfs            1.8G     0  1.8G    0% /sys/fs/cgroup
/dev/md127       494M  312M  183M   64% /boot
/dev/md124       383G  372G   12G   98% /home
tmpfs            1.8G  262M  1.5G   15% /tmp

pagefile.sys用仮想HDD作成

Oracle VM VirtualBox マネージャーを開き、仮想HDDを作成する。



仮想HDDの設定は以下の通り。

  • /tmpの中に仮想HDDファイルを作成「/tmp/swap.vdi」。
  • ファイルサイズはホストOSの空きメモリサイズやゲストOSで必要なサイズ等から決める。
  • サイズは可変サイズに設定




仮想HDDのフォーマットとpagefile.sysの作成。

ゲストOSのwindows 10を起動(メモリサイズはスワップが発生しないサイズにすること)し、スタートボタン右クリック -> ディスク管理で作成した仮想HDDをフォーマット。


スタートボタン右クリック -> システム で「システムの詳細設定」 を開き仮想メモリの設定画面を開く。


仮想メモリの設定はCドライブを256MBの固定値、pagefile.sys専用ドライブのEドライブは「システム管理」に設定。
Cドライブの256MBは安全のため設定。
「設定」ボタンを押さないと変更が反映されないので注意。


ゲストOSのwindows 10を再起動し、設定が反映されているか確認。
正しく設定されていればゲストOSをシャットダウンし、ホストOSの「/tmp/swap.vdi」を別の場所(homeディレクトリなど)にコピー、バックアップすること。
swap.vdiのファイルサイズが数十MB程度ならOKだが、100MBやGBになっている場合は失敗しており、ゲストOSに割り当てているメモリサイズを増やしてから仮想メモリ設定をやり直すこと。


仮想メモリの再設定と動作確認

ゲストOSのwindows 10に割り当てるメモリサイズを「ゲストOSが通常時に使用するメモリサイズ+200MB」程度に設定。
ゲストOSを起動し、仮想メモリの設定を再度開く。
Cドライブの仮想メモリを「なし」に設定、ゲストOSを再起動し問題なく動作するか確認。



ゲストOSのメモリ使用量を増やし、仮想メモリを正しく使用できるか確認。
メモリ使用量の増加にはwindows updateの「更新プログラムのチェック」を使用。


メモリ使用量を増加させた際に、ゲストOS、ホストOSのメモリ使用量をチェックし、メモリ不足やPCSが重くならないかチェック。問題なければOK。
ホストOSから「/tmp/swap.vdi」のファイルサイズをチェックし、バックアップ時より増えていればゲストOSが仮想メモリを使用したことになる。

仮想メモリの初期化

仮想メモリのサイズは一度大きくなると小さくなることは無いため。定期的に初期化しなければホストOSのメモリを圧迫する。
ゲストOSのwindows10をシャットダウン、バックアップしたswap.dviを/tmp/swap.vdiに上書き。
ゲストOSを起動し、ゲストOSが仮想メモリを認識、サイズが初期化されているか確認。問題なければOK。

処理の自動化

  • ゲストOS終了後に「/tmp/swap.vdi」を削除。
  • ゲストOS起動前にバックアップしたswap.vdiを/tmp/swap.vdiにコピー。
  • /tmp/swap.vdiのサイズをチェックし、肥大化していたらゲストOSを再起動し、/tmp/swap.vdiを初期化。
これらの処理を自動化したPerlスクリプを作成。
引数に「start」、「stop」、「ifrestart」を渡すことで動作が変わる。

$vbox_win10_id ゲストOSのマシンID 「vboxmanage list vms」コマンドで調べる。
$default_swap_path バックアップしたswap.vdiのパス


#!usr/bin/perl

use strict;
use warnings;
use Time::Piece;
use feature ':5.10';

our $vbox_win10_id = 'VBOX_ID';
our $default_swap_path = 'swap.vdi';
our $tmp_swap_path = '/tmp/swap.vdi';
our $stop_timeout = 60; #sec
our $restart_swap_size = 1024*1024*1024; #sec


if($ARGV[0]){
  given($ARGV[0]) {
    when ('start') { &start(); }
    when ('stop') { &stop(); }
    when ('ifrestart') { &ifrestart(); }
  }
}


sub start{
  if(!&isRunning($vbox_win10_id)){
    print "\nstart win10\n";

    #swap.vdi の初期化
    system("cp $default_swap_path $tmp_swap_path");

    system("/usr/bin/vboxheadless -s $vbox_win10_id &");
  }else {
    print "win10 is Running\n";
  }
}


sub stop{
  if(&isRunning($vbox_win10_id)){
    print "\nstop win10\n";

    print `/usr/bin/vboxmanage controlvm $vbox_win10_id acpipowerbutton`;


    #swap.vdi の削除
    #メモリ解放
    my $endT = time + $stop_timeout;
    while((-f $tmp_swap_path) and ($endT>time)){
      if(!&isRunning($vbox_win10_id)){
        unlink $tmp_swap_path;
        print "delete $tmp_swap_path\n";
        last;
      }

      sleep 1;
    }
  }else {
    print "win10 is Stopping\n";
  }
}

sub ifrestart{
  if(&isRunning($vbox_win10_id)){
    if(-f $tmp_swap_path){
      my $swap_size = -s $tmp_swap_path;
      if($swap_size>$restart_swap_size){
        print "\nrestart win10\n";
        print "swap size : $swap_size\n";
        &stop();
        &start();
      }
    }
  }else {
    &start();
  }
}

sub isRunning{
  my ($id) = @_;
  my $runlist = `/usr/bin/vboxmanage list runningvms`;

  if($id and $runlist and $runlist =~ /$id/s){
    return 1;
  }
  return 0;
}


2016/10/25追記

動かなくなっていたので原因と修正方法を記述。
上に書いたスクリプトをcrontabやsystemdで動かす場合。仮想マシンを作成したCenots7ユーザでスクリプトを動かすこと。

rootで動かすと作成した仮想マシンを見つけられず「invalid machine name or uuid」というエラーを出力する(仮想マシンファイルの保存場所が各ユーザのホームディレクトリ内に作られるのが原因)。

また、「/tmp/swap.vdi」がroot所有者で作成されるため、一般ユーザでスクリプトを動かしたときに「/tmp/swap.vdi」を上書きできずエラーとなるためスクリプトが動かなくなる。
こうなった場合は「/tmp/swap.vdi」をroot権限で手動削除すること。

crontab 記入例(上のスクリプトをwin10boot.plに保存)
$ crontab -l
20 * * * * /usr/bin/perl /home/user/win10boot.pl ifrestart

0 件のコメント:

コメントを投稿