0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C#】超怖い話~増え続けるメモリ使用量!!!~

0
Last updated at Posted at 2026-03-21

0.はじめに

怖い話を聞くのは好きだが、体験はしたくない。
少し前に怖い体験をした。
そこから少しばかりの学びを得たので、共有したいと考え、
この記事を書いているところだ。

1.恐怖の扉が静かに開く(数行の修正と設定変更)

資格がとりたい。
痩せたい。
旅行に行きたい。
宝くじを当てたい

やりたい事、叶えたいことがあるのに時間が無い、運が無い。
新規開発も多く、やりがいはあるが仕事が忙しすぎる。
この開発が終われば、上記4つが叶うはず!!!
開発も終盤に差し掛かっていた。
顧客による受け入れ試験中のある日。

タスクスケジューラーで、ある時間ごとに実行していた プログラムを24時間起動 するようにしてほしいとの要求が出た。

それぐらいなら別にいいか。
今までの我儘に比べたら可愛いものだ
無限実行するように、プログラムの一部(数行程度)を書き換えた。
顧客の環境に入り設定を行った。
このタスクスケジューラーでの無限実行が地獄の一番地への誘いになるとは。。。

「そう単純な話のはずだった。」

2.不穏な連絡(「CPU使用率が日々増加しているようです」)

設定してから、数日たった時チャットが入ってきた。
「〇〇(顧客名)さんのサーバーの動作が重いらしいんです。」

顧客の情シスからは数日前からCPU使用率が上がり始めているとの事だった。
性能が芳しくないサーバ使ってるから、予期せぬ暴走か?
と失礼なことを考えていた。
タスクマネージャーを調べるとあるプロセスの挙動が目についた。
何か、時間ごとにじわじわとメモリ使用量が増えているプロセスがある。
xxxx.exeというプロセスだ。
これは、数日前にタスク登録したあのプログラムだ。
背中に冷たいものを感じる。

3.調査開始(どんなプログラムだったのか)

(1)設定ファイル(json)から設定値(10種類くらい)を読み込み
(2)(1)で指定された入力ファイルを読み込み、帳票ファイルを1種類から10種類出力
(3)(1)、(2)を5秒ごとに繰り返す。
上記のように記載すると単純だが、複雑な処理が多い。

4.メモリリークへの施策(これで解決か?)

これまでほとんど意識する事のなかったメモリリーク対策を勉強してみる。
本来は、C#ではメモリ開放を意識しなくてもいいのだが、
頻繁に大量のデータの追加などが起きる場合、強制的にメモリ開放する必要があるという事がわかった。
問題のプログラムも、多くのリストやファイル出力を使っている。
以下のメソッドを処理の終了時に使うことにした。

  • リスト.Clear()
  • リスト.TrimExcess()
  • GC.collect()

簡単なサンプルプログラムを作って、上記の効果を確認している。

とにかく上記3ステップを書くと、メモリ使用量が「爆発的に、革命的」に減少する。

ついでにできる事なら、私の体重も減少させて欲しい(心の声)

だが、改善しないのだ。
地味なコメントアウトとステップ実行により
、上記3ステップが効く場合と効かない場合が見えつつあった。

5.メモリ使用量が増加するソース例

ここで以下のプログラムを作成してみた。

  • 10組のlotoの組み合わせをテキストファイルを出力
  • appsettings.jsonに種類と最大数字を設定
  • これを無限回繰り返す

下記のソースにも、メモリ増加するコードが隠れている。
お分かりだろうか?

Program.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
namespace console_jsonloto
{
 internal class Program
 {
  static void Main(string[] args)
  {

   while (true)
   {

    var builder = new ConfigurationBuilder()
     .SetBasePath(Directory.GetCurrentDirectory()) // 実行ファイルのある場所
     .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

    IConfiguration config = builder.Build();
    //ロトの種類
    int type0 = int.Parse(config.GetSection("Loto_Settings")["type"]);
    //最大数字
    int lotomax = int.Parse(config.GetSection("Loto_Settings")["max_num"]);
    StreamWriter wt = new StreamWriter(@"C:\work\loto_1.txt", false);

    Random rand = new Random();

    for (int i = 0; i < 10; i++)
    {
     List<int> lotoqp_list = new List<int>();
     int nn;
     for (int j = 1; j <= lotomax; j++)
     {
      lotoqp_list.Add(j);
     }
     int[] numloto = new int[type0];

     for (int j = 0; j < type0; j++)
     {
      nn = rand.Next(lotomax - j);
      numloto[j] = lotoqp_list[nn];
      lotoqp_list.RemoveAt(nn);
     }
     var orderlist = numloto.Select(x => x).OrderBy(x => x);
     wt.WriteLine(string.Join(",", orderlist));
     lotoqp_list.Clear();
     lotoqp_list.TrimExcess();
     GC.Collect();
    }
    wt.Close();
    wt.Dispose();
    Thread.Sleep(2000);
   }
  }
 }
}
appsettings.json
{
  "Loto_Settings": {
    "type": 6,
    "max_num": 43
  }
}

出力例

7,18,19,31,35,43
2,3,9,30,33,40
16,19,23,25,28,39
1,15,29,31,42,43
1,4,17,23,24,36
3,7,13,24,29,35
1,2,7,18,19,41
3,15,17,18,23,28
1,2,8,27,29,31
6,9,20,28,35,43

6.最終章(犯人はお前だ!!!)

犯人は以下のコードの中にある。

    var builder = new ConfigurationBuilder()
     .SetBasePath(Directory.GetCurrentDirectory()) // 実行ファイルのある場所
     .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

『ConfigurationBuilder()を使う際に、
reloadOnChange: trueを何気なく使っていたことが原因でメモリ使用量の増加していたのだ。』

※trueと設定していると、常にappsetttins.jsonが変更されているか、
監視しているためメモリー使用量が増大する。

解決案:reloadOnChange: falseとする

7.まとめ

24時間365日稼働させたいプログラムには、明示的なメモリ開放が必要になることがある。
有効な施策は以下。

  • configurationbuilderを使ったjsonファイル読み込みでは、reloadOnChange: falseとする。
  • リスト.Clear()
  • リスト.TrimEccee()
  • GC.Collect()
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?