[ラズパイ] Pico W でネットワークリクエストを繰り返すとENOMEMエラーが発生する場合

投稿者: | 2024-03-17

Pico W で5秒おきにリクエストを送信するプログラムを実行してみます。

import utime
import network
import urequests

#Wi-FiのSSIDとパスワードを設定
ssid = ''
password = ''

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.disconnect()
wlan.connect(ssid, password)

# 接続が確認できない場合は1秒おきに再確認する(最大10回)
max_wait = 10
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1
    print('waiting for connection...')
    utime.sleep(1)

# 接続できない場合はエラーを返す
if wlan.status() != 3:
    raise RuntimeError('network connection failed')
else:
    print('Connected')
    status = wlan.ifconfig()
    print('ip = ' + status[0])
    
    # ここで通信処理
    for i in range(1, 10):
        url = 'https://******'
        print('i = %d' % i)
        r = urequests.get(url)
        utime.sleep(5)

    # 切断
    wlan.disconnect()
    print('Disconnect')

すると以下のようなエラーが発生しました。

waiting for connection...
waiting for connection...
waiting for connection...
waiting for connection...
Connected
ip = 192.168.11.10
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
Traceback (most recent call last):
  File "<stdin>", line 36, in <module>
  File "requests/__init__.py", line 180, in get
  File "requests/__init__.py", line 83, in request
OSError: [Errno 12] ENOMEM

何回か実行しても同じタイミングで送信時にエラーが発生していました。

調べてみた結果、どうやらPico W の使用可能なメモリの空きが足りなくなったようです。

というわけで、使用可能なメモリの容量をガベージコレクションを使って確認してみます。

import gc

# 省略

    # ここで通信処理
    for i in range(1, 10):
        url = 'https://******'
        print('i = %d' % i)
        r = urequests.get(url)
        print('mem_free = %d' % gc.mem_free())
        utime.sleep(5)

実行結果は以下の通りです。

waiting for connection...
waiting for connection...
waiting for connection...
waiting for connection...
Connected
ip = 192.168.11.10
i = 1
mem_free = 158336
i = 2
mem_free = 131376
i = 3
mem_free = 104416
i = 4
mem_free = 77456
i = 5
mem_free = 50496
i = 6
Traceback (most recent call last):
  File "<stdin>", line 36, in <module>
  File "requests/__init__.py", line 180, in get
  File "requests/__init__.py", line 83, in request
OSError: [Errno 12] ENOMEM

今回の場合、1回のリクエストでメモリを26,960バイト使用していて、徐々にメモリの空き容量が減っているのが分かりました。

メモリの空き容量を増やすために、リクエストを送信する前にガベージコレクションの実行を追加してみます。

    # ここで通信処理
    for i in range(1, 10):
        url = 'https://******'
        print('i = %d' % i)
        gc.collect()
        r = urequests.get(url)
        print('mem_free = %d' % gc.mem_free())
        utime.sleep(5)

実行結果は以下の通りです。

waiting for connection...
waiting for connection...
waiting for connection...
waiting for connection...
Connected
ip = 192.168.11.10
i = 1
mem_free = 158944
i = 2
mem_free = 133520
i = 3
mem_free = 110528
i = 4
mem_free = 110528
i = 5
mem_free = 110528
i = 6
mem_free = 110528
i = 7
mem_free = 110528
i = 8
mem_free = 110528
i = 9
mem_free = 110528
Disconnect

使用可能なメモリが維持され、無事10回リクエストの送信ができました。

ガベージコレクションについては詳しくないので毎回実行するのが良いのかは分かりませんが、とりあえず繰り返しリクエスト送信したい場合はこれで対処できそうです。


gc — ガベージコレクションの制御

https://micropython-docs-ja.readthedocs.io/ja/latest/library/gc.html