【Python入門】メモリの解放や効率的に使う方法をマスターしよう!

こんにちは! プログラマーのakiraです。

Pythonでアプリケーションを快適に動作させるためには、メモリの操作・開放についての知識は必要になります。

ガベージコレクションってなんだろう?
メモリ解放ってどうやってやるんだろう?
どうやってメモリを効率的に使用すればいいのだろう?

と疑問に思ったことはないでしょうか?そんな方に向けて、基礎からメモリの開放や効率的に使う方法について以下の内容で解説していきます。

  • 【基礎】メモリの基礎
  • 【実践】Pythonでメモリを開放する方法
  • 【実践】メモリを効率的に使う方法

本記事ではPythonでメモリを扱う方法について、初心者でもわかりやすく解説していますので、ぜひ参考にしてください!

本記事を読む前に、Pythonがどんなプログラミング言語なのかをおさらいしておきたい人は次の記事を参考にしてください。

→ Pythonとは?特徴やできること、活用例をわかりやすく簡単に解説

目次

メモリについて考えてみよう!

メモリとは

メモリとはPC上でデータを一時的に記憶しておく場所です。変数などに格納したデータを高速に処理する必要があるプログラミング処理ではメモリとうまく付き合っていくことが重要になるのです!

それではこれからプログラミングとメモリの関係について詳しく見ていきましょう!

ガベージコレクションとは

ガベージコレクションとはあるプログラムで確保したメモリの内、不要になったメモリを自動的に解放してくれる機能になります。プログラミングをしていると変数にデータを格納したり、ファイルからデータを読みこんだりして、メモリ上に必要なデータを読み込んで、様々な処理を実行します!

しかしメモリへ読み込んだデータは必要な処理が完了したら、その後の処理では必要のないゴミデータとなってしまいますよね?そこでPythonなどの言語では、Garbage Collector(ごみを集める人)が登場するわけです。PCなどのメモリは無限に使えるわけではなく、数ギガバイトなどの限界があると思います。

このガベージコレクタが不要になったゴミデータをメモリから開放してくれることで、メモリ上にゴミデータが溢れてしまうことを防ぐのです!

メモリリークとは

「ガベージコレクションとは」で、ガベージコレクタが不要になったゴミデータをメモリから開放してくれる役割を担っていることを説明しました。それでは、メモリ上にゴミデータが溢れてしまった場合はどうなるのでしょうか?メモリの使用可能な容量がどんどん減っていってしまいますよね?

この使用可能なメモリ領域がどんどん減っていき、PCやサーバなどの不具合を招くバグをメモリリークというのです!

Pythonでメモリ解放の方法を確認しよう!

これまで説明してきたようにPythonにはGC(ガベージコレクション)の機能があるため、メモリ開放はC言語などのように手動で実施することなく、大抵はGCが自動で行ってくれます。そのため普段はメモリについて大きく意識することなくプログラミングの処理を書くことに専念できるのです!

しかし大量のデータを扱う場合やメモリ制限のある環境では、GCの判断で開放を行うのではなく、必要なくなったタイミングで即座に開放したい場合も出てきます。次項でPythonのメモリを手動で開放する方法について見ていきましょう!

delで要素を削除してみよう!

それではdelで要素を削除する方法について見ていきましょう。以下のようにすることで、delで要素を削除することができます。

del 要素

それでは次のサンプルコードを見ていきましょう!
delでdel_testを削除後、del_testが参照できなくなっていることがわかるかと思います!

del_test = ["memory del test"] * 10
print(del_test)

del del_test

print(del_test)

実行結果

['memory del test', 'memory del test', 'memory del test', 'memory del test', 'memory del test', 'memory del test', 'memory del test', 'memory del test', 'memory del test', 'memory del test']
Traceback (most recent call last):
  File "del.py", line 6, in <module>
    print(del_test)
NameError: name 'del_test' is not defined

gc.collectでメモリ解放してみよう!

それでは、メモリを開放する方法について見ていきましょう!

まずdelで解放したい要素を削除し、gc.collect()でメモリを強制的に開放することにより、メモリを再利用することができるようになります!

import gc

gc_test = ["memory del test"] * 10
del gc_test
gc.collect()

メモリを効率的に使う方法を検討してみよう!

今度はメモリを効率的に使う方法について考えていきましょう。プログラミングでメモリ問題を引き起こすものの一つとして、巨大なファイルの読み込みがあります。メモリに乗らないような数十GBの巨大なファイルを一気に開きメモリが足りなくなってしまうと、メモリリークなどの不具合を引き起こしてしまうことがあります!

最悪の場合、サーバ上の処理全体が停止し、サービス止まってしまう場合もあるのです。Pythonでメモリを効率的に使用する方法をマスターして、メモリエラーを未然に防げるようにしましょう!

それでは、次項以降で読み込みに使用するサンプルのCSVを以下のコードより作成しておいてください!

l = []
for i in range(100):
    l.append(str(i) + ',sample,csv')

with open('sample.csv', 'w') as f:
    f.write('n'.join(l))

以下のような内容が記載されたCSVファイルが作成されます!

sample.csv

0,sample,csv
1,sample,csv
2,sample,csv
.
.
98,sample,csv
99,sample,csv

yieldを使う

それでは、yieldを使用してメモリを効率的に使う方法を考えていきましょう!

yieldとは処理を一時的に停止させて値を返すことができる機能です。またこのyieldを使用するとジェネレータという反復可能なオブジェクトを作ることができます!

yieldやジェネレータって何?という方はこちらの記事を見てください!

では、サンプルコードを見ていきます!

関数file_generatorではファイルを渡すとファイルの中身を一行ずつ返してくれるジェネレーターを生成します。実行結果は、print(next(gen))でsample.csvの1、2、3行目を表示しています!

def file_generator(file):
    with open(file, encoding="utf-8") as f:
        for line in f:
            yield line

file_path = 'sample.csv'
gen = file_generator(file_path)

print(next(gen))
print(next(gen))
print(next(gen))

実行結果

0,sample,csv

1,sample,csv

2,sample,csv

このようにyieldを使用してファイルの中身を一行ずつ返すジェネレーターを作成することによって、ファイル全体をメモリ上に読み込む必要がなくなるのです!

次は作成したジェネレーターをfor文でループしてみましょう!
ファイルの中身を一行ずつ取得し、全行表示することができます!

def file_generator(file):
    with open(file, encoding="utf-8") as f:
        for line in f:
            yield line

file_path = 'sample.csv'
gen = file_generator(file_path)

for line in gen:
    print(line)

実行結果

0,sample,csv

1,sample,csv

2,sample,csv
.
.
.
97,sample,csv

98,sample,csv

99,sample,csv

pandasでchunksizeを指定する

次は、pandasを使用してメモリを効率的に使う方法を考えていきましょう。pandasとはデータを効率的に処理できるPythonのデータ分析ライブラリです。

pandasって何?という方は、以下のページに詳しく解説されています!

またpandasのread_csvでCSVを扱う方法は、以下のページに解説されています!

それではサンプルコードを見ていきましょう。pandasは、csvファイルを読み込む際にchunksizeという一度にメモリ上に読み込む行数を指定できます。今回は、chunksizeを10に指定しているため一度に10行ずつ読み込む事かできます!

import pandas as pd

reader = pd.read_csv('sample.csv', encoding='utf-8', chunksize=10, header=None)

print(next(reader))
print(next(reader))

実行結果

   0       1    2
0  0  sample  csv
1  1  sample  csv
2  2  sample  csv
3  3  sample  csv
4  4  sample  csv
5  5  sample  csv
6  6  sample  csv
7  7  sample  csv
8  8  sample  csv
9  9  sample  csv
     0       1    2
10  10  sample  csv
11  11  sample  csv
12  12  sample  csv
13  13  sample  csv
14  14  sample  csv
15  15  sample  csv
16  16  sample  csv
17  17  sample  csv
18  18  sample  csv
19  19  sample  csv

print(next(reader))を2回実行しているため、10行ずつ0~9、10〜19行を読み込むことができていますね。次のように全行取得したい場合は、for文でループすることにより10行ずつ全行を取得することができます!

import pandas as pd

reader = pd.read_csv('sample.csv', encoding='utf-8', chunksize=10, header=None)

for i in reader:
    print(i)

実行結果

   0       1    2
0  0  sample  csv
1  1  sample  csv
2  2  sample  csv
3  3  sample  csv
4  4  sample  csv
5  5  sample  csv
6  6  sample  csv
7  7  sample  csv
8  8  sample  csv
9  9  sample  csv
     0       1    2
10  10  sample  csv
11  11  sample  csv
12  12  sample  csv
.
.
.
87  87  sample  csv
88  88  sample  csv
89  89  sample  csv
     0       1    2
90  90  sample  csv
91  91  sample  csv
92  92  sample  csv
93  93  sample  csv
94  94  sample  csv
95  95  sample  csv
96  96  sample  csv
97  97  sample  csv
98  98  sample  csv
99  99  sample  csv

daskを使用する

今度はdaskを使用した効率化の方法を考えていきましょう!

daskとは柔軟な並列計算を行うライブラリです。つまり、daskではメモリに乗らないようなファイルでもdask側で調整して分散処理を行ってくれるため、巨大なファイルも扱うことができるようになります。メモリ上に読み込む量もdask側で調整してくれるため柔軟な処理が可能となります!

それでは、daskを使用してサンプルのCSVファイルを読み込んでみましょう!

import dask.dataframe as dd

reader = dd.read_csv('sample.csv', encoding='utf-8', header=None)

print(reader.compute())

実行結果

     0       1    2
0    0  sample  csv
1    1  sample  csv
2    2  sample  csv
.
.
.
98  98  sample  csv
99  99  sample  csv

[100 rows x 3 columns]

このようにdaskが調整してファイルを読み込み、分散処理をしてくれるため巨大なファイルも高速に扱うことができるのです!

まとめ

いかがでしたでしょうか。今回は、Pythonのメモリについて学習しました!

メモリについて考えたり、メモリを意識したプログラミングをすることは、初級から中級プログラマにステップアップする上でも大切なことですので、しっかり理解して活用できるようにしていきましょう!

この記事を書いた人

インフラエンジニア→プログラマー。趣味は3歳の子供にPCの使い方、タイピングを教えること。業務ではPython, PHP, Javaなどやってます。

目次