ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Java質問&情報提供サイトコミュのメモリ確保。。

  • mixiチェック
  • このエントリーをはてなブックマークに追加
メモリ内に領域を割り当て割り当てに成功すると割り当てられた領域へのポインタを返し,失敗すると NULL が返し使用後にはfree関数を呼ぶmallocってやつがC言語でありますよね?

それを、Javaでもやりたいんですが、APIを探しても対応するメソッドがなかったのでどうすれば良いですか?

とある、参考書によると、new演算子を用いて動的にメモリを確保して、使用後は何もする必要もなく、使用されなくなったメモリは自動的に回収されるってあったんですが使い方がいまいち分りません。。newはインスタンス生成に使うやつ知らなかったので。。

次のC言語の関数をJavaにしたときのnew を使ったメモリ確保の表記を教えてもらいたんですが。。課題作成中に行き詰ってしまって。よろしくお願いします。


// 入力引数: depth : ディレクトリのビット長
// 戻り値 DIRECTORY : ディレクトリ
DIRECTORY *create_directory(int depth) {
DIRECTORY *directory ;
directory = (DIRECTORY *)malloc(sizeof(DIRECTORY) * (unsigned int)pow(2, depth)) ; // 2のべき乗倍の領域を確保
if (directory == NULL) {
fprintf(stderr, "領域確報に失敗しました\n\n") ;
exit(EXIT_FAILURE) ;
}
return directory;
}

コメント(51)

お。つっこみありがとございます>Stradaさん
つまり、オールドタイプとして生きてきたということですか???う。。うぅぅぅ

#ずっとVector受けしてましたよ・・・・orz まぁ閉じた構造の中でしか使ってないから
#いいけど・・・orz
#三つ子の魂か・・・・怖い怖い・・・

ま、どうでもいいですけど


>ぴーのすけさん

情報ありがとうございます。なるほど。勉強になりました。

CollectionsクラスのsynchronizedList(List)
Collections#synchronizedList(List) されてる Listってことですね。

メモメモ
Java 2でCollectionフレームワークなるものが導入されて、
その関係で、VectorがListの実装クラスとなりましたね。

通常、Collectionの実装クラスを、クラス変数またはインスタンス変数として持つことが多いのですが、そうだとするとVectorを使ってもスレッドセーフにはならない関係でしょうか、Java 2以降で追加されるクラスは、スレッドセーフでないものばかりですね。
みなさんどうもありがとうございます。

>>JavaにはまるまるPointerは存在しません。参照です。。。
しかし、逆にPrimitive以外は、すべて参照で「ポイント」しています。つまり言うと
すべてが「Pointer」であるかのような状態です。

ですよね。これは勉強しました。Javaでは、構造体を直接参照するときも、->ではなく、.で良いってやつですよね!

>>インスタンス生成にmallocが含まれていますので、newだけでいいです。

これは知らなかったです。勉強になります。

>>DIRECTORYはJavaらしく「Directory」にして、
ご質問をJava的に書くと次のようになります。

Directory createDirectory(int depth) {
  return new Directory();
}

↑これだけで良いんですか??

それと

ArrayList list = new ArrayList();

も調べたんですがいまいち使い方が。。listに値をいれるって、2のべき乗で猟奇を確保するってのを入れれば良いんですかね?

>>2のべき乗で猟奇を確保する必要があるならば、そういう配列オブジェクトを作ります。

ってのもよく意味が分りません。。難しいですね。。


例えば以下のように配列を作成して返します。

public Directory[] createDirectory(int depth){
return new Directory[Math.pow(2.0, depth)];
}

おそらく、元のcreate_directory関数と等価なメソッドは上記のようなものです。
この返された配列に対して、newしてDirectoryを格納することになります。
typoしてた。

newしてDirectory -> newしたDirectory


あ、powの結果ってdoubleか

public Directory[] createDirectory(int depth){
return new Directory[(int)Math.pow(2.0, depth)];
}

コンパイラとか通してないから、怖いなw
失礼、ちょっと混乱させていますね

2のべき乗で猟奇→2のべき乗で領域です。

List型は、いわゆる「List」です。 CでLinkedListって書いたことないですか?
#LinkedListはListの実装方法の一種です。

#余談ですけど、クイックソートをC++のLinkedListで書いたときは、気持ち良いぐらい
#すっきりとして、感動したもんです。

大きさを気にしないで、値を格納するための器だと思ってください。
使い方は

List list = new ArrayList();
list.add(value)

注意:
Primitive型を直接いれることはできません。
ゆえに以下のコードは1.4以前はコンパイルエラーです。

list.add(1);
list.add(2.0);

これをいれたきゃ
list.add(new Integer(1));
list.add(new Dowbule(2.0));

1.5以降は (やったことないから,、本当にそうかわからないけど)
AutoBoxingで自動的に解決されるから
list.add(1)もOKかもしれないorz

#個人的にAutoBoxingはキライ

>14
をよんでの感想

主さん・・・基本的にJavaをJavaととらえずにCとの違いだけを勉強して
Javaを習得しようとしてませんか? 正しいですけど
構造化言語のCとJavaの違いなんて、スタートのところでかなり違うんで
最終的な違いの量ははんぱないと思うんですよね。大変じゃないかな
と思います。

#私は C-> C++ -> Javaだったんでわりとすんなりだったなぁ〜 
#みなさんはどういう順序で学習しました?
#最初からJavaって人がかなりうらやましい

包括的にJavaを勉強する中でCとの違いを楽しむってアプローチ
になるんじゃないかなぁ〜本当は・・・と


#もしくは、性急になにかのCプログラムを、Javaで書き直す
#必要でもあるのかな・・と

違っていたらごめんなさい。ただ、今の話の流れだと
class = 構造体のおきかえととらえ

何がしかのクラス.main() = Cのmain関数ととらえ・・・・

最終的には Javaで構造化言語使うのと変わらないっていう
アレな状態ができあがることが目に浮かぶのです。。。。

そうならないようにがんばってください。


============はしがき

昔は、実メモリの管理ですらプログラマの責任で、
OverRayの実装すらも、プログラマがやっていたのです。
C + 仮想メモリでその必要がなくなり、それでも抽象化されたアドレスの利用が
プログラマの責任であったのが

Java + 仮想マシンでさらに抽象化され、プログラマの手元から離れた。
で、その代わり、Javaプログラマの考えるメモリインターリープは
gcの対象となりえるか。。。ってことが主なテーマに・・・ってどうでもいいか


拡張ハッシュ。。
例えば。
00,01,10,11
の4項目を2個のばけつに入れます。
どのばけつにどの項目を入れるかをルール決めします。例えば、先頭1バイトが0か1かで選り分けるとします。
この「0か1」を擬似キーとゆー事にします。
これでばけつの見分け方はわかりました。
次は、ばけつ自体へのアクセス方法が必要です。全てのばけつへの参照を持った容器/枠をつくります。索引ですね。ディレクトリと呼ぶ事にします。
ディレクトリはばけつへの参照を
[ばけつ1][ばけつ2]
のように連続して配置させておきます。
こうする事で、00を取り出したい→擬似キーは0→ディレクトリから一番最初のばけつを取得→ばけつの中の00がとれた!
さて。
Cのソースだと、ディレクトリはばけつへの参照を連続アドレスで保持します。
Javaはそーゆー事できないので、配列かリストにします。
OK?

仕事に戻りますっ
トピ主さんへ

#10 は誤りでした、すみません。
#17 を参照してください。
みなさんどうもありがとうございます。

17>>を参考にしたらなんとか出来まし。

どうもありがとうございます!
> 13
> そうだとするとVectorを使ってもスレッドセーフにはならない関係でしょうか

意味がよくわかりませんが、何か勘違いしている雰囲気が漂っているような
#22

class A {

Vector v = new Vector(); //インスタンス変数

public void add(Object o){
  v.add(o);
}

public void printAll(){
  for(int i=0; i<v.size(); i++){
    System.out.println(v.get(i).toString());
  }
}

}

これがスレッドセーフかどうかです。
どう書こうがVector自体はスレッドセーフでは?
Aがスレッドセーフかどうかは知りません。
13で言っていることは、Vector自身がスレッドセーフかどうかではなく、
「Vectorを使っても23のAがスレッドセーフになるわけではない」
ということでは。
13の文章が何を言っているのかよく理解できません。
「Vectorを使えばスレッドセーフになるから、追加されたクラスはスレッドセーフでないものばかり」というのなら話はわかります。

23は、Vectorがスレッドセーフになってくれているので、vが保持している値の出し入れに関する部分ではスレッドセーフでしょう。


だんだん話題がずれてきましたね。
せっかくのいい話題だと思いますので、話題ずらしていきましょう(汗)

そうなんですよ。我が社でもよく誤解されている人が多いのですが、
#23のコードはスレッドセーフではないのです。

あるスレッドがprintAll()を実行中に、別のスレッドがadd()を実行したら、
どうなるでしょうか?というふうに見れば、理解してもらえると思います。

というわけで、スレッドセーフを謳っているVectorでも使い方によってはスレッドセーフではありませんね。なので、J2SE以降ではスレッドセーフなコレクションクラスを作らなくなったのではないかというのが #13 でお伝えしたかったことなのです。
>>27
printAllでは
「呼び出し開始時点のvの中身が出力される」
ことを期待しているとします。
(printAllに対して期待する内容が違えばこの限りではありません)

printAllの実行途中に、別スレッドがaddを実行すると
printAllの呼び出し開始時点とは異なる値が出力されます。
-----------------------------------------
・開始時点:v={1,2,3} → 期待される出力:1,2,3
printAll中に別スレッドがadd("5")した場合・・・
・実際の出力:1,2,3,5
-----------------------------------------
>>28
うお、かぶっちゃいましたね。
失礼しました。
少なくとも、以下のようにした方がいいでしょう。
public void printAll(){
  //for(int i=0; i<v.size(); i++){
  //  System.out.println(v.get(i).toString());
  //}
  for (Iterator it = v.iterator(); it.hasNext();) {
System.out.println(it.next());
  }
}

イテレーション中に変更があった場合ConcurrentModification例外がスローされます。
詳しくはVectorのJavaDocを読むとフェイルファスト等について書いてあります。

出力程度なら問題は小さいですが、総和や平均を求める等の処理を行っている場合、気づかずに流れてしまうと後で問題が起きたときの特定が難しいので、気をつけたいところですね。


余談ですが次のような便利なものが用意されています。
List list = Collections.synchronizedList(new ArrayList(...));
#31

>余談ですが次のような便利なものが用意されています。
>List list = Collections.synchronizedList(new ArrayList(...));

#12で話題にされていますね。
これですべてが解決できるという誤解があるので、
#13、#23でコメントしました。

#31のコードはAクラスがスレッドセーフでないことを前提とするなら許容範囲内かもしれませんが、ConcurrentModificationExceptionに依存したプログラミングは避けるべきだとVectorに書かれていますね。
>スレッドセーフって1メソッド内の処理で同期がとれていればスレッドセーフと言われるんですよね?
そうとは限らないでしょ。
複数メソッドが共有するオブジェクトだってあるし。
>33
あ、読んでませんでした。お恥ずかしい。
> 37
> 普通は1Business処理でDB更新までするし、Listを使いまわさないから

そのListがBusiness Logicクラスの属性になってるという前提?
なら問題でしょ。
スレッドセーフの厳密な定義はわかりませんが・・・

>>37
複数スレッドからアクセスがある処理で
「INPUTに対して仕様と異なるOUTPUTが出てくる」
ことがなければ、スレッドセーフと言っていいと思います。

このとき、より下位の処理自体(例えばVectorとか)が
スレッドセーフであることは必要条件ではありません。

23の例でも、v(下位の処理)が非同期なArrayListであったとしても
Aが適切な同期を取れば、A自体(上位の処理)はスレッドセーフになります。
スレッドセーフというのは、複数のスレッドが共有しているインスタンスの内部データに矛盾が起きないということです。

実をいうと、#22はサンプルとしてはあまりいい例ではありませんでした。
改めて書きます。

class A {
  Vector v = new Vector(); //インスタンス変数

  public void add(Object o){
    v.add(o);
  }
  public void remove(Object o){
    v.remove(o);
  }
  public void printAll(){
    for(int i=0; i<v.size(); i++){
      System.out.println(v.get(i).toString());
    }
  }
}

このAクラスのインスタンスを複数のスレッドで共有する場合、使い回しているうちにIndexOutOfBoundsExceptionがスローされる場合があります。
ということを理解できれば問題ないと思います。
#41の補足

A.printAll()でIndexOutOfBoundsExceptionがスローされる場合があります。
#41は、1つのスレッドからしかアクセスできないようにメソッドを修飾してもダメでしょうか?
>いくら下位のListのようなクラスがスレッドセーフなつくりになっていても、
>上位のBusiness Logicクラスがきちんと同期処理をせずListにAddして
>Getしていたらその上位クラスはスレッドセーフじゃないと言われるのかな?
>って不思議に思っただけです。

いや、その通りだと思いますよ。
逆に、スレッドセーフと謳われている継承可能なクラスはフックメソッドによりスレッドセーフが壊れたらまずいです。

ところで、実際にテンプレートメソッドパタンをそういう風に使うのは珍しいですね。もちろん良い方法と思いますが、実践例をあまり知らないので驚きました。
#43

私はスレッドセーフでない例を示しただけであって、
どうやってスレッドセーフにするかという話までしていないです。

#45

そんなに単純な話ではないでしょう。

1についてはたぶん、そのご理解で問題ないと思います。

2についてはちょっと理解できませんでした。
また、インスタンス変数でも場合によっては同期処理を行う必要がない場合もあります。

3の「メソッド変数」であっても、それがFileOutputStreamのインスタンスであれば、同期+ファイルのロック処理を行う必要があります。DBでも同じことが言えます。
ReentrantReadWriteLockクラスを使用し、工夫すれば、ある程度の共有メモリのリスクは回避できますよ。

現プロジェクトで導入してるとこ一部あります。
ずいぶん話が進んでいてびっくりです。

皆さんが展開されている話にはあまりついて行けていないので、私の書いた部分についての話題だけにふれます。

じつは#22のクラスAを一見して「明らかにスレッドセーフでしょう」と思ったのですが、そうでないことはその後の説明でわかりました。
#41のソースで言うと、
    for(int i=0; i<v.size(); i++){ ------(1)
      System.out.println(v.get(i).toString()); --------(2)
(1)で要素数を取得した後に他のスレッドが要素を追加したら最後の要素が表示されません。(実装によっては別の要素ですね)
(1)から(2)の間で逆に要素が削除されていたら、(2)で最後の要素を表示しようとしていたときは、おそらくArrayIndexOutOfBoundsExceptionが投げられるようですね。

ただ、ここで出る例外はやはりクラスAの作りによるもので、言い方を変えればVectorクラス自身の仕事はきちんとスレッドセーフに果たしているはずです。

ですから、Vectorはスレッドセーフであり、クラスAはスレッドセーフではないとなります。

スレッドセーフなクラスを使っているからと言ってそれを利用したものが簡単にスレッドセーフになるわけではないと言う、簡単に思いこみで判断をするなというかある意味当たり前の事を再認識させられました。
ひとつ勉強になりました。
補足など

#31
>  for (Iterator it = v.iterator(); it.hasNext();) {
> System.out.println(it.next());
>  }

>イテレーション中に変更があった場合ConcurrentModification例外がスローされます。

#33
>ConcurrentModificationExceptionに依存したプログラミングは避けるべきだとVectorに書かれていますね。

#34
>Iteration先に変更があった場合にConcurrentModification例外が投げられるの
っては全然知りませんでした。またそれを信じるなって言うのも(笑)

これは信じるなと言うことではなく、「そんなことの起きないようなプログラムを作るべきで、この例外は出バグのために使うべき」といった趣旨の記述がVectorのAPIドキュメントに書いてあったと思います。

あと、#41のクラスをスレッドセーフにする方法も考えてみました。
  public void printAll(){
    synchronized(v) {
      for(int i=0; i<v.size(); i++){
        System.out.println(v.get(i).toString());
      }
    }
  }

こんな風にして他のVectorのaddやremoveメソッドなどと同様にvのロックを取得すればいいんじゃないかと思います。
> #46
あっそうですね。勘違い(はやとちり?)していました、失礼いたしました。
>45

1
定数というのはfinal staticという意味ですか?
それなら定数だからスレッドセーフというのは間違いです。
逆に定数でなくてもスレッドセーフというケースはあります。

2
全ての移譲クラスをnewしてしまえば問題なし、というのは確かに正しいですね。

3
スレッドセーフじゃないオブジェクトを扱う可能性を考慮する必要があります。

ログインすると、残り17件のコメントが見れるよ

mixiユーザー
ログインしてコメントしよう!

Java質問&情報提供サイト 更新情報

Java質問&情報提供サイトのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。