ページ 11

メモリ解放に制限?

Posted: 2017年5月29日(月) 14:48
by MNV
あるライブラリ(Opencv)の某クラス(Mat)のobject中のデータpointer (uchar* data)を外部からfreeを使って解放しようとしたら、いつも例外を起こします。
このクラス自身にはrelease()メソッドがあって、おそらくこれが本来dataを解放してくれる仕組みですが、でも、C++にはクラスの外部からメンバーpointerが指しているメモリを解放できないようにする(Eg,例外が起きる)仕組みがあるのでしょうか。

ご教授お願い致します。

Re: メモリ解放に制限?

Posted: 2017年5月29日(月) 16:27
by usao
質問内容が把握し難いです.

(A)うっかり free 等によって,外部からメンバをいじくれてしまうのは良くないので,そういうことをできないようにしたいのだが,禁止する方法はあるか?
(B)「(uchar* data)を外部からfreeを使って解放しようとしたら」何故例外が起こるのか?

のどちら(あるいはそれ以外)でしょうか.

オフトピック
>あるライブラリ(Opencv)の某クラス(Mat)のobject中のデータpointer (uchar* data)を外部からfreeを使って解放しよう

何故わざわざそんなことをするのでしょう…?

Re: メモリ解放に制限?

Posted: 2017年5月29日(月) 19:40
by 白い変人
確かに、状況がイメージし難いところはありますね。

外部から開放という事は、そのポインタのアクセス制限がどの様に宣言されているのかにも依る部分はある気がします。

また、C++に関しては、newで確保したメモリをfreeで開放しようとするのもNGと思われます。

その他、そもそも既に開放されているアドレスにfreeを掛けようとしている可能性もあるかもしれません。

最後に、これはあまり言いたくはないのではありますが、メモリ関連に関しては、コンパイラのバグで正常に開放できなくなるケースも、稀にですが確認されてはいます。(その場合、コンパイラを変えるか、コードの書き方をちょっと変えるだけで動いたりする場合もあります。)

Re: メモリ解放に制限?

Posted: 2017年5月29日(月) 22:41
by YuO
MNV さんが書きました:あるライブラリ(Opencv)の某クラス(Mat)のobject中のデータpointer (uchar* data)を外部からfreeを使って解放しようとしたら、いつも例外を起こします。
C/C++のライブラリは自分がどこにメモリを割り当てたかを知っていることができます。
そして,aligned_alloc, calloc, malloc, reallocで返されたポインタ (free/reallocで解放されたものを除く) 以外をfreeに渡した場合は未定義の振る舞いとなっていますから (C11の場合。7.22.3.3),
「自分が割り当てて返したのでは無いポインタ」を検出し,何らかの例外機構 (C++の例外だとか,WindowsのSEHだとか,signalだとか) で通知してもおかしな振る舞いではありません。
MNV さんが書きました:このクラス自身にはrelease()メソッドがあって、おそらくこれが本来dataを解放してくれる仕組みですが、でも、C++にはクラスの外部からメンバーpointerが指しているメモリを解放できないようにする(Eg,例外が起きる)仕組みがあるのでしょうか。
少なくとも標準C++にそのような機構はありません。

そもそも,最初に書いてある例外は誰が出した例外ですか。
Matクラスでではなく,free関数が送出した例外ではないでしょうか。

Re: メモリ解放に制限?

Posted: 2017年5月30日(火) 09:24
by MNV
YuO様とその他の方々、ありがとうございます。

YuO様が書かれました:
==========
少なくとも標準C++にそのような機構はありません。

そもそも,最初に書いてある例外は誰が出した例外ですか。
Matクラスでではなく,free関数が送出した例外ではないでしょうか。
==========
非常に建設的なご意見有難うございます。
もう少し説明させていただきます。
OpencvのMATに public fieldとして uchar* dataが定義されてあります。
これはMat instanceを生成する時にOpencvのほうより自動的にメモリ空間を確保されます。 簡単な構造(uchar)なので freeか、deleteで解放できるはずと思って、解放しようとしたら、freeもdeleteも delete[] も三つの解放方法で同じ実行例外が発生してしまいました。
例外発生メッセージ「XXX.exeによってブレークポイントが発生しました。」
場所:「delete_scalar.cpp」 中の下記関数:

コード:

void _CRTDECL operator delete(void* const block) noexcept
{
  #ifdef _DEBUG
       _free_dbg(block, _UNKNOWN_BLOCK);
  #else
       free(block);
  #endif
}
============================
free(...)の場合は実行エラーメッセージ同じですが、上記関数に飛びません。

あらゆるアイディア、ご教授に感謝します。


}
[/code]
Mat自身にはrelease()というメソッドがあり、これで恐らくdetaが指しているメモリを解放してくれるだろうと思います。

Re: メモリ解放に制限?

Posted: 2017年5月30日(火) 11:11
by usao
>簡単な構造(uchar)なので freeか、deleteで解放できるはずと思って、解放しようとした

そもそも,クラスが管理している領域をどうして強引に解放しようと思うのかが全く意味不明です.
「やったらどうなるのか?」という実験なのでしょうか.

cv::Matは 参照カウンタ方式によるメモリ管理を行っている わけで,その管理対象たる領域を勝手にfreeだのdelete[]だのしてしまえば,
Matが正規の手続きの中でその領域を解放しようとした際に2重解放になってしまい,そこで例外が出るということでしょう.
(そんなメンバが何でpublicなんだよ……とは思いますが)


>Mat自身にはrelease()というメソッドがあり、これで恐らくdetaが指しているメモリを解放してくれるだろうと思います。

release()については,リファレンスマニュアルに
Decrements the reference counter and deallocates the matrix if needed.
と,明確に説明してあります.
>恐らく
とか想像するよりも,使用するライブラリのリファレンスを見た方が手っ取り早いのではないでしょうか.

Re: メモリ解放に制限?

Posted: 2017年5月30日(火) 16:23
by MNV
usao 様
貴重なご意見ほんとうにありがとうございます。
Matは複雑すぎで、dataの中身がdatastartメンバーにも設定されて、
勝手にいじたら、不整合が生じます。
当初、dataを解放する目的として新規Matを生成せず、他の関数からもらったデータpointerで更新したかったんですが、無理ですね。(そのために前の領域を解放しねければメモリリークになってしまうので)

dataにデータをcopyするのは遅いし、どうすれば良いのでしょうか。

Re: メモリ解放に制限?

Posted: 2017年5月30日(火) 17:34
by usao
Matにデータ領域を生成&管理させる使い方をせずに,
外部データをvoid*型で引数に受けるタイプの Mat のコンストラクタを利用すると良いかもしれません.
(その場合,Matはその外部データ領域を解放しませんので,解放が必要な領域を用いるならば適切に対処する必要があります.)

Re: メモリ解放に制限?

Posted: 2017年5月30日(火) 18:54
by 結城紬
MNV さん

OpenCV の Mat クラスには使い方が2種類あります。
ひとつは、通常の Mat クラス内部でバッファの確保・開放をすべて管理するタイプ。
もうひとつは、外部からポインタを渡して、バッファの確保・開放は Mat クラスではなく外部で(プログラマーが自分で)管理するタイプです。
今回 MNV さんがやりたいことは後者だと思います。
例えば以下のように使います。

コード:

void *pData; ← 自分で確保・開放する領域
...
Mat m(480, 640, CV_8UC3, pData);
サイズやチャンネル数を指定する方法が幾つかバリエーションがありますので、詳しくはリファレンスマニュアルを参照してください。

Mat クラスの data メンバは、計算処理の高速化のために読み書きしたり、外部のライブラリに渡したりするために公開されているものです。
勝手に開放したり、外部からアドレスを変更したりしてはいけません。
Mat クラスのメンバ変数で直接見る必要があるのは cols と rows の2つくらいで、余計なことを考えなければ全然複雑なクラスではありません。
後は基本的にメンバ関数を通して操作します。

Re: メモリ解放に制限?

Posted: 2017年5月31日(水) 10:39
by MNV
結城紬 様

ご指摘の方法でやって見たらOKでした。
助かりました!

再度皆様にお礼を申し上げます。