Unityを使用していてRelease of invalid GC handle. The handle is from a previous domain. The release operation is skipped.というエラーが発生したのでこちらの記事で紹介します。
いつ起きたか?
UnityとASP.NET Coreとの間でデータを送受信するときに発生しました。
今までは普段通りに動いていましたが、突然、このエラーが発生しネットワーク通信が
できなくなりました。
原因はネットワーク通信で発生するメモリリーク
エラー文をChatGPTに質問してみると以下のような回答が出ました。
「Release of invalid GC handle. The handle is from a previous domain. The release operation is skipped.」というエラーメッセージは、ガベージコレクション(GC)ハンドルが無効であることを示しています。ここで「ハンドル」はメモリ管理のために使われる参照のようなもので、このエラーメッセージは、そのハンドルが「前のドメイン」からのものであることを意味します。
簡単に言うと、ハンドルが現在のメモリ管理領域(ドメイン)では有効ではないため、リリース操作がスキップされたということです。このエラーは、特にアプリケーションがドメイン(例えば、AppDomain)をまたいで動作している場合に発生することがあります。具体的には、メモリが誤って管理され、既に解放されているメモリ領域にアクセスしようとしたり、異なるドメイン間で無効になったオブジェクトにアクセスしようとした場合に発生することが考えられます。
解決方法としては、コードが適切にドメインを管理しているか、オブジェクトやハンドルが正しく解放されているか確認する必要があります。場合によっては、コードの再設計やガベージコレクションの制御を見直すことが求められるかもしれません。
以下の文が重要そうです。
特にアプリケーションがドメイン(例えば、AppDomain)をまたいで動作している場合に発生することがあります。具体的には、メモリが誤って管理され、既に解放されているメモリ領域にアクセスしようとしたり、異なるドメイン間で無効になったオブジェクトにアクセスしようとした場合に発生することが考えられます
ドメインについて記述されているので、ネットワークの通信間でエラーが発生し、
メモリを開放するガベージコレクションが実行されず、メモリリークが発生していると思われます。
UnityWebRequestの記述に問題があった
UnityWebRequestの記述に問題がありました。
IEnumerator PostRequest()
{
// POSTリクエストの作成
var request = new UnityWebRequest(apiUrl, "POST");
byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonData);
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
// リクエストを送信してレスポンスを待機
yield return request.SendWebRequest();
// エラーが発生したときの処理
if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError(request.error);
Debug.LogError("通信に失敗しました");
}
// 通信に成功したときの処理
else
{
Debug.Log("通信に成功しました!");
}
}
上記のコードで
var request = new UnityWebRequest(apiUrl, "POST");
という箇所がありますが、UnityWebRequestを使うときには
使い終わった時にDispose()を呼び出さないとメモリが溜まってしまい、メモリリークが発生していた
のだと思われます。
下記の記事が参考になります。
しかし、Dispose()を書くのは忘れがちなので、usingを使って処理を書いた方が良いです。
今回はusingを使って処理を書き換えました。
公式リファレンスでもusingを使うことを推奨しています。
※修正後のコード
IEnumerator PostRequest()
{
// ★修正
using (var request = new UnityWebRequest(apiUrl, "POST"))
{
byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonData);
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
// リクエストを送信してレスポンスを待機
yield return request.SendWebRequest();
// エラーが発生したときの処理
if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError(request.error);
Debug.LogError("通信に失敗しました");
}
// 通信に成功したときの処理
else
{
Debug.Log("通信に成功しました!");
}
}
}
UnityWebRequestをusingで囲ってリソースの破棄を自動的に行うようにしました。
こちらにするとDispose()を書く必要がないので便利です。
usingについてはこちらも参考にしてもらえるとわかりやすいと思います。
コメント