アカウント名:
パスワード:
malloc/freeの処理コストってどれくらいかかるんだろう。メモリがバカ高かった時代はmalloc/freeで使用量を厳密に、というのはわかるんだが、ンGB当たり前の昨今、malloc/freeの処理コストの方が高くなったりしないのかな?と。「だいたい、こんくらいとっといてぇー」というようなプログラミングスタイルは無いのだろうか、と思う。
・・・malloc/free叩いとらんな、最近。
>malloc/freeの処理コストの方が高くなったりしないのかな?>と。「だいたい、こんくらいとっといてぇー」というようなプログラミングスタイルは無いのだろうか、と思う。
チマチマ何回かに分けて取るより一回にまとめて取った方が相対的に安くなるので、「だいたい、このくらい」でまとめて取ってから、それをアプリ内部でチマチマ切り刻んで使うというテクニックは昔からあったと思います。
そしてJVMなんかだと、それを自動でやってくれるので、Javaな人にとってはこれも「もうやらなくていい昔のコーディングテクニック」の一つですね。
それから、OSが仮想記憶をサポートして以降は、mallocは実メモリを確保するわけではなくOSの管理テーブルに予約するだけなので、ちょっとくらい大きい領域を予約しても影響はすごく小さくなってるはずです。
>チマチマ何回かに分けて取るより一回にまとめて取った方が相対的に安くなる>ので、「だいたい、このくらい」でまとめて取ってから、それをアプリ内部で>チマチマ切り刻んで使う
それを普通mallocと呼びます。OSからまとめて取るのはその内部で使われてるsbrk/mmap/VirtualAlloc等
>そうか、Javaだと(よほど変なことをしない限り)メモリリーク心配しなくていいのか(本当?)
いえいえ、お馬鹿なコードを書くとリークしていきますよ。使わなくなったオブジェクトに対する参照をつかんだままにしてればいくらでもメモリ使用量は増えていきますから。
スコープを外れた変数のつかんでるオブジェクトの回収とかは勝手にやってくれますが変数参照が生き残っていれば回収できないのです。プログラムグローバルなキャッシュを何も考えずに書かせると、そんなコードができるんじゃないですかね。ただ、まぁ、そうはいってもCに比べれば格段に問題のあるコードは書きにくくなっているでしょうね。
>>そうか、Javaだと(よほど変なことをしない限り)メモリリーク心配しなくていいのか(本当?)>いえいえ、お馬鹿なコードを書くとリークしていきますよ。
「メモリリーク」という単語を、「ポインタ(或いは参照)を全て手放したにもかかわらず、領域の解放(free)を 忘れたために、メモリを少しずつ食い尽くしていく現象」と定義するなら、Javaだと「メモリリーク」の心配はほぼありません。#まさに「よほど変なことをしない限り」、且つ「VMやフレームワークにバグがない限り」。#C言語で長期間動作するアプリを作るのが難しいのは、このような「狭義の#メモリリーク」の検出とデバッグが難しいからで、Javaではそれが発生しない#ことがサーバー向けアプリに適している理由でもあります。
少なくとも昔は「メモリリーク」というのはそういう意味で使われているものだと思っていましたが、最近では参照を掴んだまま離さない「到達可能なオブジェクト」=「(GC的に)生きているオブジェクト」が生き残っているのも「メモリリーク」だと呼ぶ人はいます。そういう「広義のメモリリーク」ならばJavaでも起こりえます。#これはGCの基本的な特性なので、おそらく他のGCを持つ言語でも同じになる。
でもこれは言うまでもなくC言語でも他の言語でも起こることですね。そういうコードしか書けない人は、いずれにせよC言語で長期間安定動作するようなコードは書けないので、Javaにおける広義のメモリリークの心配をするには十年早いかと。
御指摘の通り、長期運用を考慮していないという意味で問題だと思います。
ただ、Javaに限定した場合、最大メモリ使用量が予め設定されているので、(その範囲を超えないという意味で)OS側への影響は与えにくいですね。JVMで確保したメモリ内で段々と空き領域が減っていく・・・という話になります。
# 個人的にはOS上のメモリ使用量しか見てない運用者というのがいて、# JVM内のメモリ使用量を把握していない例が多いのが頭痛の種。(T-T
>運用者にとっては区別する意味が全くない。>この話を聞いて私が思い出す言葉は「五十歩百歩」です。プログラミングが分かってない人の意見かな。
運用者にとっては違わないかもしれないけど、開発者にとっては全然違いますよ。
狭義のメモリリークはデバッグが凄く難しい。それに比べ広義のメモリリークは対応が遥かに容易。
結果として、開発に同じだけのリソースを割り振った場合に、Cで作った場合は開発期間が長期化しメモリリークが多く不安定で、Javaで作った場合は短い開発期間でもメモリリークが少なく安定する、という違いとなって現れることが多い。
もちろん無限の開発コストと無限の開発期間がつぎ込める場合はこの限りではありません。
結果を区別する必要は無いけど、原因を区別する必要は有るね。
区別する気が無い人なら運用者にもならないで欲しい。なぜならその人は、バグったときにその区別ができるような情報をデバッグ者に渡す「気」が無いわけでしょ?
そういうところで情報断絶をおこしてデバッグが立ち往生すること、実際凄く多いんだよorzつまりそういう場合にバグがいつまでたっても直らないのはハッキリいってそいつのせい。
全く気にする必要が無い人はそれはエンドユーザというんだよ。運用者じゃない。
運用者は開発者とともに原因と結果の界面に居る人だ(でないと困る)。両方に目配りをしてもらいたい。
>>運用者にとっては区別する意味が全くない。>>この話を聞いて私が思い出す言葉は「五十歩百歩」です。>プログラミングが分かってない人の意見かな。
>運用者にとっては違わないかもしれないけど、開発者にとっては全然違いますよ。
>狭義のメモリリークはデバッグが凄く難しい。>それに比べ広義のメモリリークは対応が遥かに容易。
狭義/広義と使い分けているが、ただ単にスキル不足な気がする。昔ならいざ知らず、統合開発環境が主流な現在においてはどちらも容易。(ブレークポイント張りまくれるでしょ。スタックの中身ですら見えるでしょ。)プログラミングが分かってない人の意見かな。<
>昔ならいざ知らず、統合開発環境が主流な現在においてはどちらも容易。>(ブレークポイント張りまくれるでしょ。スタックの中身ですら見えるでしょ。)
ブレークポイントはどこで何が発生するか分かってないと張っても無駄です。
(狭義の)メモリリークの難しい点は、それを発生させる条件を特定することや、或いはそもそもメモリリークの有無を知ることそのものなんですよ。どういう条件の時にメモリリークが発生するのかまで特定できていれば、その部分のバグについては8割方片付いたも同じです。
ブレークポイントはその残りの2割のさらに一部を楽にできる程度の効果しかありません。#そもそも統合開発環境がある前からデバッガなんてありましたよ。#ブレークポイントをはったりもやってた。でも(狭義の)メモリリークは#最も面倒なバグの一つとして有名だったのです。
>出来ない君集団にやらせるなら、何使わせても一緒じゃね!?この部分についてだけは同意。
> でもこれは言うまでもなくC言語でも他の言語でも起こることですね。そういう> コードしか書けない人は、いずれにせよC言語で長期間安定動作するようなコードは> 書けないので、Javaにおける広義のメモリリークの心配をするには十年早いかと。おかしくね?Javaにおける広義のメモリリークを起こすようなコードを書く人はその心配をしたほうがいいんでは・・・?
>#まさに「よほど変なことをしない限り」、且つ「VMやフレームワークにバグがない限り」。>#C言語で長期間動作するアプリを作るのが難しいのは、このような「狭義の>#メモリリーク」の検出とデバッグが難しいからで、Javaではそれが発生しない>#ことがサーバー向けアプリに適している理由でもあります。
これ、素直に初耳なんですけど。。サーバ向けアプリで知っているとすれば、銀行勘定系(COBOL)のフロントUI位なんですが、そんなに、サーバー向けアプリ+Javaって多い!?また、開発言語の選択基準がメモリの確保/解放が決め手になるなんて、どんだけ幼稚なんだと
>サーバ向けアプリで知っているとすれば、銀行勘定系(COBOL)のフロントUI位なんですが、>そんなに、サーバー向けアプリ+Javaって多い!?
むしろ日本の銀行だけが未だにCOBOLとかを使っているガラパゴスで、外資系金融機関などはのきなみJavaへのリプレースが済んでるそうですよ。
Googleも元は90年代に作られたのでC言語だったけど、とっくにJavaを使う方向に変更されてるし。
>また、開発言語の選択基準がメモリの確保/解放が決め手になるなんて、どんだけ幼稚なんだと。。これは「大間違い」です。
Javaがサーバーサイドで利用される理由は、マルチスレッドとの親和性、豊富なライブラリ、パフォーマンス、高い生産性など、それらの総合評価によるものです。決してGCが「決めて」になったわけではありません。
しかし、もしそれらのメリットがあったとしても、もしメモリリークを引き起こしやすい言語であれば、これほどまでに利用されることはなかったかもしれません。それくらいメモリリークはサーバーサイドでは厄介な問題と言えるのです。
>メモリの解放忘れをメモリリークと呼ぶのも問題無いと思うが?いえ、「解放を忘れてる」のだけではなく「動いている」のです。
#車で言えば、「赤信号で停車している」のではなく、#「アクセルを踏んだままにしている」くらいの差がある。#アクセルを踏んだままなので、エンジンを止めるわけにはいかないのです。
これ、素直に初耳なんですけど。。サーバ向けアプリで知っているとすれば、銀行勘定系(COBOL)のフロントUI位なんですが、そんなに、サーバー向けアプリ+Javaって多い!?
一時期、DBを叩くWEBアプリをTomcatのようなJavaフレームワークで構築するのが流行りましたよ。今時はマシンパワーが上がったのでPerlやPHPやRubyを使うようになりましたけど。
また、開発言語の選択基準がメモリの確保/解放が決め手になるなんて、どんだけ幼稚なんだと。。<確かにそんな話する、トンでも外注(害虫!?)もいることにはいるけどなぁ。。
既出っぽいですけどメモリアロケーションの実体が言語インタプリタにあると言うのはメンテナンスの面からはやりやすいのですが。コンパイラでネイティブコードにした物を動かした場合のこの手のバグ潰しのややこしさを考えると…
まぁ、純粋にCだけで書いて必要なメモリは必ずmalloc噛ます。構造体すら一度mallocして割り当ててしまう。とかそういう非常に神経質にやる場合は例外として、下手なC++コンパイラとかみたくオブジェクトバンバン作って後で変な残りカスが出てしまうというのはどこにバグの責任所在があるか見極めるのが非常に難しい。特に多くのプロセスが立ち上がったり消えたりを繰り返す場合には見えないメモリリークの蓄積で仮想記憶領域を食いつぶし、マシン飛ばしたり速度落としたりとか普通にありますよ。# MPU自体が完璧に近いガベージコレクション機能を持てばC++も信頼出来るようになるのですが、# 今はOSカーネルのGC機能とコンパイラの正確さ頼みだからな…
動的メモリを確保できる言語は、メモリリークの問題を常に持っている。この位の事を理解していないと、言語の種類なんか関係なくロクなコードなんか書けないと思けど。
このあたりは[全体|詳細]設計とか誰にどこのコーディング振るかというプロジェクトマネージメントとかの問題でコーディングに入る前に理詰めで潰せていないとどうしょうもないですよ。それでもコーディングに入ったら最初はリークバリバリになりがちで、それが書き方の問題か組み合わせの問題か容易に見分けられる準備していないと。一つ一つのルーチンがメモリリーク潰せていても、組み合わせた場合にどうかというのはまた違う。設計段階でメモリリーク誘発しにくいように見極めが出来ていないとダメなのでは。
少なくとも Visual C++ では、メモリーを確保して解放しないことを「メモリーリーク [microsoft.com]」と呼んでいます。日本語版のドキュメントでは「メモリ リークとは、割り当て済みのメモリを正しく解放できない状態を指します」と、わかったようなわからないような説明になっているので、英語版 [microsoft.com]から引用します。
One of the most subtle and hard-to-detect bugs is the memory leak―the failure to properly deallocate memory that was previously allocated.(訳: 最も微妙で最も見つけにくいバグの一つがメモリーリーク、すなわち確保したメモリーを正しく解放しないことである。)
One of the most subtle and hard-to-detect bugs is the memory leak―the failure to properly deallocate memory that was previously allocated.
(訳: 最も微妙で最も見つけにくいバグの一つがメモリーリーク、すなわち確保したメモリーを正しく解放しないことである。)
failureとあるので、(プログラマがメモリを解放しようとしたにもかかわらず)失敗した、というニュアンスでしょう。
failure は「何かをしようとして失敗すること」とは限りません (例 [alc.co.jp])。とはいうものの、おっしゃる通り、「failure to deallocate」という英語の解釈としては「プログラマーはメモリーを解放しようとしているにもかかわらず (何らかの理由で) 解放に失敗すること」というのもありえますね。メモリーリークというのはそういう意味ではないと思っていますが、証拠を挙げるのは僕には難しいです。
え?Javaでもマルチスレッド処理なんかでは一見GCにより開放されると思われる箇所でもメモリーリークを起こしますよ。中規模以上のプロジェクトで2~3件の頻度ですが...
もしかしてConservative GCのことを語っている?
malloc/freeはシステムコールなので呼ぶとコンテキストスイッチが発生します。特にCPUのクロック数よりもL2キャッシュのヒット率とかのほうが性能的影響が大きいようなメモリレイテンシにシビアなシステム、例えば、マルチスレッドでサイズの大きいヒープを頻繁に生成/開放しながら沢山のアクセスを受け付けるサーバーアプリみたいな処理系では、コンテキストスイッチのオーバヘッドが馬鹿にならないので、JVMや.Netのようにヒープの大枠確保しておいて、プロセス内部でcpu user timeでやりくりするメモリ管理があったほうが性能的には有利。というもんだと理解しとります
>ページフォルトが後からじんわり効いてくるのがいやな場合には>プログラムの初期化部分で大きめに malloc して memset してから>free しとく必要がありますね。
メモリに十分な余裕がある場合、(ページアウトしているデータを復元するのではなく)単に新しい物理ページ割付のためのフォルトが気になることって、ありますかね?
逆にそのレベルでも気になる状況なら、memsetくらいではダメで、plock等の物理メモリロックを使わないとダメでしょう。
こないだまではdlmalloc/dlfree、最近はjemalloc/jefreeを愛用しております。
operator new と operator delete を差し替えただけで、処理速度が5倍くらい速くなってびっくりしました。
数GBの画像データを複数枚読み込んで比較するプログラムをCで組んでいたりするのでmalloc(てかcalloc)とかfreeとか頻繁に使ってますが何か。
ファイル名指定に256バイト/512バイトのcharを確保しているのも無駄知識だろうなぁ。8の倍数でメモリ領域確保したほうが効率がいいなんて都市伝説?まだそのおまじないは意味がある?
近代の都市伝説では、SIMD命令を使えるようにとか、キャッシュラインのサイズとかの都合で、16の倍数にしなくてはなりません。最近の処理系では16バイトアライメントでメモリ確保してくれるmallocとかもありますね。
もし Windows 向けだとしたら、最近は Unicode API が基本 + Unicode ベースのファイル名指定では 32767 文字までサポートなので、全然足りない場合がありうるという話に。 大抵のアプリが対応してないパスになりますけど。
# TCHAR が char じゃなく wchar_t なんですよね、_UNICODE だと。
>Unicode ベースのファイル名指定では 32767 文字まで
CreateFile() の話であれば、32000文字までですね。
>Unicode ベースのファイル名指定では 32767 文字までCreateFile() の話であれば、32000文字までですね。
MSDN Library 英語版の CreateFile 関数の説明 [microsoft.com]には 32767 文字と書かれており、日本語版 [microsoft.com]でも「ほぼ 32,000 ワイド文字」となっているので、「32767 文字までではなく 32000 文字までだ」という主張は誤りだと思います。ただ、 File Names, Paths, and Namespaces [microsoft.com] には
Note: The maximum path of 32,767 characters is approximate, because the "\\?\" prefix may be expanded to a longer string by the system at run time, and this expansion applies to the total length.
と書かれており、 32767 文字ぎりぎりまで使えるとは限らないみたいなので、 32000 文字くらいまでに抑えておいた方が安全という事情はあるかもしれません。僕は \\?\ なんて使ったことがなく、よく知りません。
>MSDN Library 英語版の CreateFile 関数の説明 [microsoft.com]には 32767 文字と書かれており
情報ありがとうございます。知りませんでした。
言い訳をすると、昔は、英語版MSDN にも nearly 32,000 としか書かれてなかったんですけどね…(This lets you use paths that are nearly 32,000 Unicode characters long.)
言い訳をすると、昔は、英語版MSDN にも nearly 32,000 としか書かれてなかったんですけどね… (This lets you use paths that are nearly 32,000 Unicode characters long.)
ということは、日本語版が「ほぼ 32,000 ワイド文字」という謎の書き方になっているのは、以前の英語版の影響なんですね。参考になります。
往年のfree論争を思い出すなあ…
あの問題(というか論争)が解決してるかといえば、いっこうにしてないよなあ。それが証拠に「終了するのにすごくすごく時間がかかるアプリ」は未だに多い。ほんとに「アプリ終了間際でのメモリ開放はOSがまとめて面倒見れる(からアプリではする必要が無い)」のならば、その処理はアプリに依存せず非同期におこなえるはずだから、プロセス終了はいつでも瞬時に終わる(ようにOSを構成する)ことは十分できるはずなんだが?
まあ、日本の?IT業界は、にわかエンジニアの方が権限が強いうえに余計なちょっかい出してくることが多いからね。
某最大手SIerでfreeするとメモリが即座にOSに返却されると思ってる連中が大勢いて無駄な修正を強要されたりとか...
>freeするとメモリが即座にOSに返却される
10数年前なら、それは勘違いと言える状況が多かったけれど、今どきはどうなんでしょうね。ある程度以上のサイズの確保/開放であれば、上記の挙動をするmalloc/free実装が多くなっている印象があります。(その場合、malloc実装側は brk() ではなく mmap() を使っていたはず)
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
「毎々お世話になっております。仕様書を頂きたく。」「拝承」 -- ある会社の日常
時々思うんだが (スコア:3, 興味深い)
malloc/freeの処理コストってどれくらいかかるんだろう。メモリがバカ高かった時代はmalloc/freeで使用量を厳密に、というのはわかるんだが、ンGB当たり前の昨今、malloc/freeの処理コストの方が高くなったりしないのかな?と。「だいたい、こんくらいとっといてぇー」というようなプログラミングスタイルは無いのだろうか、と思う。
・・・malloc/free叩いとらんな、最近。
-- gonta --
"May Macintosh be with you"
Re:時々思うんだが (スコア:2, 興味深い)
>malloc/freeの処理コストの方が高くなったりしないのかな?
>と。「だいたい、こんくらいとっといてぇー」というようなプログラミングスタイルは無いのだろうか、と思う。
チマチマ何回かに分けて取るより一回にまとめて取った方が相対的に安くなる
ので、「だいたい、このくらい」でまとめて取ってから、それをアプリ内部で
チマチマ切り刻んで使うというテクニックは昔からあったと思います。
そしてJVMなんかだと、それを自動でやってくれるので、Javaな人にとっては
これも「もうやらなくていい昔のコーディングテクニック」の一つですね。
それから、OSが仮想記憶をサポートして以降は、mallocは実メモリを確保する
わけではなくOSの管理テーブルに予約するだけなので、ちょっとくらい大きい
領域を予約しても影響はすごく小さくなってるはずです。
Re:時々思うんだが (スコア:1)
>チマチマ何回かに分けて取るより一回にまとめて取った方が相対的に安くなる
>ので、「だいたい、このくらい」でまとめて取ってから、それをアプリ内部で
>チマチマ切り刻んで使う
それを普通mallocと呼びます。OSからまとめて取るのはその内部で使われてるsbrk/mmap/VirtualAlloc等
Re: (スコア:0)
そうか、Javaだと(よほど変なことをしない限り)メモリリーク心配しなくていいのか(本当?)でも起動時に1GByte以上のヒープサイズが必要ですとかいわれると、いくらメモリ安くなったとっていってもすこしひくなぁ。
Re:時々思うんだが (スコア:1)
>そうか、Javaだと(よほど変なことをしない限り)メモリリーク心配しなくていいのか(本当?)
いえいえ、お馬鹿なコードを書くとリークしていきますよ。
使わなくなったオブジェクトに対する参照をつかんだままにしてれば
いくらでもメモリ使用量は増えていきますから。
スコープを外れた変数のつかんでるオブジェクトの回収とかは勝手にやってくれますが
変数参照が生き残っていれば回収できないのです。
プログラムグローバルなキャッシュを何も考えずに書かせると、そんなコードができるんじゃないですかね。
ただ、まぁ、そうはいってもCに比べれば格段に問題のあるコードは書きにくくなっているでしょうね。
Re:時々思うんだが (スコア:2, 参考になる)
>>そうか、Javaだと(よほど変なことをしない限り)メモリリーク心配しなくていいのか(本当?)
>いえいえ、お馬鹿なコードを書くとリークしていきますよ。
「メモリリーク」という単語を、
「ポインタ(或いは参照)を全て手放したにもかかわらず、領域の解放(free)を
忘れたために、メモリを少しずつ食い尽くしていく現象」
と定義するなら、Javaだと「メモリリーク」の心配はほぼありません。
#まさに「よほど変なことをしない限り」、且つ「VMやフレームワークにバグがない限り」。
#C言語で長期間動作するアプリを作るのが難しいのは、このような「狭義の
#メモリリーク」の検出とデバッグが難しいからで、Javaではそれが発生しない
#ことがサーバー向けアプリに適している理由でもあります。
少なくとも昔は「メモリリーク」というのはそういう意味で使われているものだと
思っていましたが、最近では参照を掴んだまま離さない
「到達可能なオブジェクト」=「(GC的に)生きているオブジェクト」
が生き残っているのも「メモリリーク」だと呼ぶ人はいます。
そういう「広義のメモリリーク」ならばJavaでも起こりえます。
#これはGCの基本的な特性なので、おそらく他のGCを持つ言語でも同じになる。
でもこれは言うまでもなくC言語でも他の言語でも起こることですね。そういう
コードしか書けない人は、いずれにせよC言語で長期間安定動作するようなコードは
書けないので、Javaにおける広義のメモリリークの心配をするには十年早いかと。
Re:時々思うんだが (スコア:3, 参考になる)
言葉の定義がどうであろうと起きている現象がなんであろうと
問題ですね。
このメモリリークの広義/狭義(あるいはメモリリーク/メモリリテンション)って
のは良く聞く話なのだけど運用者にとっては区別する意味が全くない。
この話を聞いて私が思い出す言葉は「五十歩百歩」です。
Re:時々思うんだが (スコア:1)
御指摘の通り、長期運用を考慮していないという意味で問題だと思います。
ただ、Javaに限定した場合、最大メモリ使用量が予め設定されているので、
(その範囲を超えないという意味で)OS側への影響は与えにくいですね。
JVMで確保したメモリ内で段々と空き領域が減っていく・・・という話になります。
# 個人的にはOS上のメモリ使用量しか見てない運用者というのがいて、
# JVM内のメモリ使用量を把握していない例が多いのが頭痛の種。(T-T
Re:時々思うんだが (スコア:1)
>運用者にとっては区別する意味が全くない。
>この話を聞いて私が思い出す言葉は「五十歩百歩」です。
プログラミングが分かってない人の意見かな。
運用者にとっては違わないかもしれないけど、開発者にとっては全然違いますよ。
狭義のメモリリークはデバッグが凄く難しい。
それに比べ広義のメモリリークは対応が遥かに容易。
結果として、開発に同じだけのリソースを割り振った場合に、
Cで作った場合は開発期間が長期化しメモリリークが多く不安定で、
Javaで作った場合は短い開発期間でもメモリリークが少なく安定する、
という違いとなって現れることが多い。
もちろん無限の開発コストと無限の開発期間がつぎ込める場合はこの限りではありません。
Re: (スコア:0)
結果を区別する必要は無いけど、
原因を区別する必要は有るね。
区別する気が無い人なら運用者にもならないで欲しい。
なぜならその人は、バグったときにその区別ができるような情報をデバッグ者に渡す「気」が無いわけでしょ?
そういうところで情報断絶をおこしてデバッグが立ち往生すること、実際凄く多いんだよorz
つまりそういう場合にバグがいつまでたっても直らないのはハッキリいってそいつのせい。
全く気にする必要が無い人はそれはエンドユーザというんだよ。運用者じゃない。
運用者は開発者とともに
原因と結果の界面に居る人だ(でないと困る)。両方に目配りをしてもらいたい。
Re: (スコア:0, フレームのもと)
>>運用者にとっては区別する意味が全くない。
>>この話を聞いて私が思い出す言葉は「五十歩百歩」です。
>プログラミングが分かってない人の意見かな。
>運用者にとっては違わないかもしれないけど、開発者にとっては全然違いますよ。
>狭義のメモリリークはデバッグが凄く難しい。
>それに比べ広義のメモリリークは対応が遥かに容易。
狭義/広義と使い分けているが、ただ単にスキル不足な気がする。
昔ならいざ知らず、統合開発環境が主流な現在においてはどちらも容易。
(ブレークポイント張りまくれるでしょ。スタックの中身ですら見えるでしょ。)
プログラミングが分かってない人の意見かな。<
Re:時々思うんだが (スコア:3, 参考になる)
>昔ならいざ知らず、統合開発環境が主流な現在においてはどちらも容易。
>(ブレークポイント張りまくれるでしょ。スタックの中身ですら見えるでしょ。)
ブレークポイントはどこで何が発生するか分かってないと張っても無駄です。
(狭義の)メモリリークの難しい点は、それを発生させる条件を特定することや、
或いはそもそもメモリリークの有無を知ることそのものなんですよ。どういう
条件の時にメモリリークが発生するのかまで特定できていれば、その部分のバグに
ついては8割方片付いたも同じです。
ブレークポイントはその残りの2割のさらに一部を楽にできる程度の効果しかありません。
#そもそも統合開発環境がある前からデバッガなんてありましたよ。
#ブレークポイントをはったりもやってた。でも(狭義の)メモリリークは
#最も面倒なバグの一つとして有名だったのです。
>出来ない君集団にやらせるなら、何使わせても一緒じゃね!?
この部分についてだけは同意。
Re: (スコア:0)
> でもこれは言うまでもなくC言語でも他の言語でも起こることですね。そういう
> コードしか書けない人は、いずれにせよC言語で長期間安定動作するようなコードは
> 書けないので、Javaにおける広義のメモリリークの心配をするには十年早いかと。
おかしくね?
Javaにおける広義のメモリリークを起こすようなコードを書く人は
その心配をしたほうがいいんでは・・・?
Re: (スコア:0)
>#まさに「よほど変なことをしない限り」、且つ「VMやフレームワークにバグがない限り」。
>#C言語で長期間動作するアプリを作るのが難しいのは、このような「狭義の
>#メモリリーク」の検出とデバッグが難しいからで、Javaではそれが発生しない
>#ことがサーバー向けアプリに適している理由でもあります。
これ、素直に初耳なんですけど。。
サーバ向けアプリで知っているとすれば、銀行勘定系(COBOL)のフロントUI位なんですが、
そんなに、サーバー向けアプリ+Javaって多い!?
また、開発言語の選択基準がメモリの確保/解放が決め手になるなんて、どんだけ幼稚なんだと
Re:時々思うんだが (スコア:2, 興味深い)
・言語としてのシェアがトップクラス
・Javaをクライアントサイドで使うことは少ない(携帯Javaはそこそこ多いけど)
ということを考えると、かなり多いのでは?
> 動的メモリを確保できる言語は、メモリリークの問題を常に持っている。
一見、動的メモリ確保をしていないように見えても、メモリリークすることがあります。
g++2.9.5(だったかな)で例外をcatchするとスタックが本来の位置より数bytesせり上がるというバグがあって、長期間動かすと徐々にプロセスのメモリ使用量が増えていくという現象に出くわしました。あれは怖かった。
Re:時々思うんだが (スコア:1)
>サーバ向けアプリで知っているとすれば、銀行勘定系(COBOL)のフロントUI位なんですが、
>そんなに、サーバー向けアプリ+Javaって多い!?
むしろ日本の銀行だけが未だにCOBOLとかを使っているガラパゴスで、
外資系金融機関などはのきなみJavaへのリプレースが済んでるそうですよ。
Googleも元は90年代に作られたのでC言語だったけど、とっくにJavaを使う
方向に変更されてるし。
>また、開発言語の選択基準がメモリの確保/解放が決め手になるなんて、どんだけ幼稚なんだと。。
これは「大間違い」です。
Javaがサーバーサイドで利用される理由は、マルチスレッドとの親和性、
豊富なライブラリ、パフォーマンス、高い生産性など、それらの総合評価
によるものです。決してGCが「決めて」になったわけではありません。
しかし、もしそれらのメリットがあったとしても、もしメモリリークを引き起こし
やすい言語であれば、これほどまでに利用されることはなかったかもしれません。
それくらいメモリリークはサーバーサイドでは厄介な問題と言えるのです。
>メモリの解放忘れをメモリリークと呼ぶのも問題無いと思うが?
いえ、「解放を忘れてる」のだけではなく「動いている」のです。
#車で言えば、「赤信号で停車している」のではなく、
#「アクセルを踏んだままにしている」くらいの差がある。
#アクセルを踏んだままなので、エンジンを止めるわけにはいかないのです。
設計者の問題(Re:時々思うんだが (スコア:1)
一時期、DBを叩くWEBアプリをTomcatのようなJavaフレームワークで構築するのが流行りましたよ。
今時はマシンパワーが上がったのでPerlやPHPやRubyを使うようになりましたけど。
既出っぽいですけどメモリアロケーションの実体が言語インタプリタにあると言うのはメンテナンスの面からはやりやすいのですが。コンパイラでネイティブコードにした物を動かした場合のこの手のバグ潰しのややこしさを考えると…
まぁ、純粋にCだけで書いて必要なメモリは必ずmalloc噛ます。構造体すら一度mallocして割り当ててしまう。とかそういう非常に神経質にやる場合は例外として、下手なC++コンパイラとかみたくオブジェクトバンバン作って後で変な残りカスが出てしまうというのはどこにバグの責任所在があるか見極めるのが非常に難しい。
特に多くのプロセスが立ち上がったり消えたりを繰り返す場合には見えないメモリリークの蓄積で仮想記憶領域を食いつぶし、マシン飛ばしたり速度落としたりとか普通にありますよ。
# MPU自体が完璧に近いガベージコレクション機能を持てばC++も信頼出来るようになるのですが、
# 今はOSカーネルのGC機能とコンパイラの正確さ頼みだからな…
このあたりは[全体|詳細]設計とか誰にどこのコーディング振るかというプロジェクトマネージメントとかの問題でコーディングに入る前に理詰めで潰せていないとどうしょうもないですよ。それでもコーディングに入ったら最初はリークバリバリになりがちで、それが書き方の問題か組み合わせの問題か容易に見分けられる準備していないと。
一つ一つのルーチンがメモリリーク潰せていても、組み合わせた場合にどうかというのはまた違う。
設計段階でメモリリーク誘発しにくいように見極めが出来ていないとダメなのでは。
Re: (スコア:0)
Re: (スコア:0)
フラグメンテーションが起きるのは結果です。
たとえば、256KBの領域があるとき、100KB、1KBと確保して、100KBを解放すると、100KB+155KBの2つになります。後から200KBを確保できません。
その1KBがリークしていたら、もう200KBを確保できることはありませんが、1KBが解放されれば200KBを確保できることがあるかもしれません。
しかし、実際の問題としては必要な時に必要なメモリを確保できなければ、実行できません。
Win32アプリなんか、ちょっとスレッドを動かすと、スレッド用スタックでメモリが分断されて、256MBを超えるメモリは1つくらいしか確保できません。実際使い物にならないけど、これをメモリリークとは言わないし、言語Cとは限らない。
Re: (スコア:0)
しかしJavaなどGCのある言語では、かような場合でも自動的にコンパクションを行いますから、Cよりも本質的な部分で楽でしょう。
Cなどでは適切な順序でメモリの解放を行わないとフラグメンテーションを起こしてしてしまいますし、これが大変やっかいなバグとなることは周知のとおりです。
(フラグメンテーションがメモリリークを引き起こす、とでも言いましょうか)
メモリの解放忘れというのはごく初歩的なミスですから、メモリリークなどという大層な呼び名を頂いているとは思わなかったということです。
ただのメモリの解放忘れが引き起こす現象もメモリリークと呼ぶということであれば、認識を改めます。
Re: (スコア:0)
メモリをたくさん使いたいなら、DLLのロードアドレスやスタックの置かれる場所やサイズを、自分で指定しなきゃ。
メモリーリーク (スコア:2)
少なくとも Visual C++ では、メモリーを確保して解放しないことを「メモリーリーク [microsoft.com]」と呼んでいます。日本語版のドキュメントでは「メモリ リークとは、割り当て済みのメモリを正しく解放できない状態を指します」と、わかったようなわからないような説明になっているので、英語版 [microsoft.com]から引用します。
Re: (スコア:0)
Re:メモリーリーク (スコア:2)
failure は「何かをしようとして失敗すること」とは限りません (例 [alc.co.jp])。とはいうものの、おっしゃる通り、「failure to deallocate」という英語の解釈としては「プログラマーはメモリーを解放しようとしているにもかかわらず (何らかの理由で) 解放に失敗すること」というのもありえますね。メモリーリークというのはそういう意味ではないと思っていますが、証拠を挙げるのは僕には難しいです。
Re: (スコア:0)
具体的に、どんなOSで?
WindowsやLinuxでは、mallocやnewしたものをfree、deleteし漏らしてメモリリークしても、プロセスが終了したときには、当該のプロセスがプライベートに確保したメモリはすべて開放されますよ。
Re: (スコア:0)
もし知っていたら、後学のために教えてください。
_beginthreadex()でもCreateThread()でもスタックの開始アドレスは指定できませんが、どのようにすれば、スタックのアドレスを指定できるのでしょうか?
また、MFCなどがIEコンポーネントを使ったり、ウインドウを開いたりして、内部で使ったメモリの位置を指定したり、解放する方法も知っていたら、教えてほしいです。
64bit OSが一般的になれば、"昔のコーディングテクニック"の仲間入りですが、まだ使えるので、可能ならば知りたいです。
Re: (スコア:0)
連続したアドレス空間が必要なら、早々にVirtualAllocで予約すべし。
Re: (スコア:0)
え?Javaでもマルチスレッド処理なんかでは一見GCにより開放されると思われる箇所でもメモリーリークを起こしますよ。
中規模以上のプロジェクトで2~3件の頻度ですが...
Re: (スコア:0)
もしかしてConservative GCのことを語っている?
Re:時々思うんだが (スコア:2)
malloc/freeはシステムコールなので呼ぶとコンテキストスイッチが発生します。
特にCPUのクロック数よりもL2キャッシュのヒット率とかのほうが性能的影響が
大きいようなメモリレイテンシにシビアなシステム、例えば、
マルチスレッドでサイズの大きいヒープを頻繁に生成/開放しながら
沢山のアクセスを受け付けるサーバーアプリみたいな処理系では、
コンテキストスイッチのオーバヘッドが馬鹿にならないので、
JVMや.Netのようにヒープの大枠確保しておいて、プロセス内部で
cpu user timeでやりくりするメモリ管理があったほうが性能的には有利。
というもんだと理解しとります
Re:時々思うんだが (スコア:2)
malloc/free はシステムコールではありません。必要であれば mmap や brk などで
ヒープの大枠を確保し、確保したヒープを切り分けること自体はユーザモードで
行います。
というわけで、
> JVMや.Netのようにヒープの大枠確保しておいて、プロセス内部で
> cpu user timeでやりくりするメモリ管理があったほうが性能的には有利。
> というもんだと理解しとります
JVMや.Net のメモリ管理方式には C に対してあなたが述べたような性能的な
アドバンテージはありません。
Re:時々思うんだが (スコア:2)
ページフォルトの影響を書き忘れてました。
そうだな。。。
ページフォルトが後からじんわり効いてくるのがいやな場合には
プログラムの初期化部分で大きめに malloc して memset してから
free しとく必要がありますね。
でも JVM でもこれを避けようとしたら JVM 自体の初期化処理で
同じことをやる必要があるはず。ですんでこれは性能的な
アドバンテージというよりは、プログラムを数~十数ステップ程度、
短くできるかどうかという問題ですね。
この意味でのアドバンテージなら確かにありますね。
Re: (スコア:0)
>ページフォルトが後からじんわり効いてくるのがいやな場合には
>プログラムの初期化部分で大きめに malloc して memset してから
>free しとく必要がありますね。
メモリに十分な余裕がある場合、(ページアウトしているデータを復元するのではなく)単に新しい物理ページ割付のためのフォルトが気になることって、ありますかね?
逆にそのレベルでも気になる状況なら、memsetくらいではダメで、plock等の物理メモリロックを使わないとダメでしょう。
Re:時々思うんだが (スコア:1)
こないだまではdlmalloc/dlfree、最近はjemalloc/jefreeを愛用しております。
operator new と operator delete を差し替えただけで、処理速度が5倍くらい速くなってびっくりしました。
Re: (スコア:0)
Re: (スコア:0)
ページフォールトが高コストなので malloc も free も比較的時間がかかります。
確保して初期化した配列を使い終わったときに開放せずに保持しておき、
のちに同じサイズの配列が必要になったときに再利用するといった機構を取り入れることで
プログラムの性能が改善したりします。
Re: (スコア:0)
Re: (スコア:0)
数GBの画像データを複数枚読み込んで比較するプログラムをCで組んでいたりするので
malloc(てかcalloc)とかfreeとか頻繁に使ってますが何か。
ファイル名指定に256バイト/512バイトのcharを確保しているのも無駄知識だろうなぁ。
8の倍数でメモリ領域確保したほうが効率がいいなんて都市伝説?
まだそのおまじないは意味がある?
Re:時々思うんだが (スコア:1)
近代の都市伝説では、SIMD命令を使えるようにとか、キャッシュラインのサイズとかの都合で、16の倍数にしなくてはなりません。最近の処理系では16バイトアライメントでメモリ確保してくれるmallocとかもありますね。
Re:時々思うんだが (スコア:1)
もし Windows 向けだとしたら、最近は Unicode API が基本 + Unicode ベースのファイル名指定では 32767 文字までサポートなので、全然足りない場合がありうるという話に。
大抵のアプリが対応してないパスになりますけど。
# TCHAR が char じゃなく wchar_t なんですよね、_UNICODE だと。
Re: (スコア:0)
>Unicode ベースのファイル名指定では 32767 文字まで
CreateFile() の話であれば、32000文字までですね。
32767文字? 32000文字? (スコア:2)
MSDN Library 英語版の CreateFile 関数の説明 [microsoft.com]には 32767 文字と書かれており、日本語版 [microsoft.com]でも「ほぼ 32,000 ワイド文字」となっているので、「32767 文字までではなく 32000 文字までだ」という主張は誤りだと思います。ただ、 File Names, Paths, and Namespaces [microsoft.com] には
と書かれており、 32767 文字ぎりぎりまで使えるとは限らないみたいなので、 32000 文字くらいまでに抑えておいた方が安全という事情はあるかもしれません。僕は \\?\ なんて使ったことがなく、よく知りません。
Re: (スコア:0)
>MSDN Library 英語版の CreateFile 関数の説明 [microsoft.com]には 32767 文字と書かれており
情報ありがとうございます。知りませんでした。
言い訳をすると、昔は、英語版MSDN にも nearly 32,000 としか書かれてなかったんですけどね…
(This lets you use paths that are nearly 32,000 Unicode characters long.)
Re:32767文字? 32000文字? (スコア:2)
ということは、日本語版が「ほぼ 32,000 ワイド文字」という謎の書き方になっているのは、以前の英語版の影響なんですね。参考になります。
Re: (スコア:0)
Re: (スコア:0)
アライメントの問題ですよね。
私の時は2の倍数の処理系と4の倍数の処理系でした。
構造体とか変数とか確保するときに、宣言の順番によってメモリ使用量が変わったり、
アクセス速度が4割ほど変わったりしたのも古い思い出です。
今はそこまで速度を気にする仕事に就いていないしなぁ。
Re: (スコア:0)
往年のfree論争を思い出すなあ…
あの問題(というか論争)が解決してるかといえば、いっこうにしてないよなあ。
それが証拠に「終了するのにすごくすごく時間がかかるアプリ」は未だに多い。
ほんとに「アプリ終了間際でのメモリ開放はOSがまとめて面倒見れる(からアプリではする必要が無い)」
のならば、その処理はアプリに依存せず非同期におこなえるはずだから、
プロセス終了はいつでも瞬時に終わる(ようにOSを構成する)ことは十分できるはずなんだが?
Re: (スコア:0)
まあ、日本の?IT業界は、にわかエンジニアの方が権限が強いうえに余計なちょっかい出してくることが多いからね。
某最大手SIerでfreeするとメモリが即座にOSに返却されると思ってる連中が大勢いて無駄な修正を強要されたりとか...
Re: (スコア:0)
>freeするとメモリが即座にOSに返却される
10数年前なら、それは勘違いと言える状況が多かったけれど、今どきはどうなんでしょうね。
ある程度以上のサイズの確保/開放であれば、上記の挙動をするmalloc/free実装が多くなっている印象があります。
(その場合、malloc実装側は brk() ではなく mmap() を使っていたはず)