• 締切済み

HashMapの容量圧縮について

初期サイズがわからない状態でHashMap(Hashtableでも可)を作成し、HashMapの容量を圧縮する方法などありますか? ArrayListのTrimToSizeメソッドのようなものがあったらいいのですが、ご存知でしょうか?

みんなの回答

  • KSOH
  • ベストアンサー率93% (29/31)
回答No.4

ユースケースを拝見しましたが、少なくともHashMapを使う限りにおいては質問者さんがおっしゃるようなメモリーの節約の仕方を気にする益はあまりないと思います。 >後は、値の参照だけですので、高速にアクセスできればよく(←このためハッシュを採用)、ハッシューキーの衝突等一切考慮する必要がありません。 いえいえ、衝突はハッシュ法に関して言えば最も重要なファクターなのでユーザが気にしなくいとしてもHashMapの方で大いに気にしています。ハッシュ法はキーの衝突を避けることが性能の確保に繋がりますから。 HashMapに関して言えば内部テーブルの拡張戦略は単純で充填率がload factorを超えたところで次の2のべき乗のサイズに拡張されます。よって、最終的なテーブルのサイズを節約するためには初期サイズの指定は無関係(初期登録時の性能だけに影響)で、load factorにのみ左右されます。運よく登録キー数が2のべき乗より少しだけ小さい数であればload factor=1.0にしてやることでほぼ空きエントリーはなくなります。しかし、2のべき乗より何割か小さい数だとどうしてもそれだけの空きが生じます。結局load factor=1.0と指定したとしても充填率は最悪50%、最良100%です。充填率をそれ以上あがるような使い方(外から制御する方法)はありません。 この何割かの空き領域のサイズが本当に気になるのであればHashMapとは異なる実装のクラスを用いることになります。もしそうしたければHashMapのソースをコピーしてきてtableSizeForなどを書き換えればある程度空きが小さくなるようにできるとは思います。 ただ、ご質問のユースケースでそこまで気にすることもないと思います。

oooo111
質問者

お礼

お礼遅くなりすみません。 ありがとうございます。 英語の質問ページも見ましたが、やはりNo4さんのおっしゃるとおりでした。

全文を見る
すると、全ての回答が全文表示されます。
  • ninoue
  • ベストアンサー率52% (1288/2437)
回答No.3

>アプリケーション起動時に設定ファイルの内容をHashMapに読み込み、以降はHashMapに対して、削除、追加、更新といったことを一切いたしません。 それでしたら設定ファイルのentry数は最初に分るので、それに対応したinitial capacityを指定してHashMapをnewすれば解決するのではと思われます。 default load factor=0.75が標準のようですので、entry数が例えば15000でしたら、次のようにしてみれば良いのではないでしょうか。 HashMap myMap; .... myMap = new HashMap(20000); // 15000/0.75=20000;

oooo111
質問者

補足

ご回答ありがとうございます。 また、こちらが提供した情報が不足していたようですみません。 現在のロジックでは、設定ファイル読み込みが”逐次処理”のためHashMap作成時にはわからないです。最後の設定値をHashMapに登録した時点でわかるロジックになっています。。。 なので、ご指摘どおり設定ファイルのエントリー数がわかるようにプログラムを修正すればHashMap生成時に要素数を設定できるのですが・・・ ちょっと、そこまでロジックいじるのが面倒だったので、ArrayListのTrimToSizeみたいな便利なメソッドがあれば、1行追加で楽ができると思ってしまいました。 やはり、設定ファイルの要素数をHashMap生成時にわかるように修正するしかないですかね。。。?

全文を見る
すると、全ての回答が全文表示されます。
  • KSOH
  • ベストアンサー率93% (29/31)
回答No.2

何故ハッシュ法を使用しているのにテーブルを圧縮しようとするのでしょうか?どういったケースなのかもう少し説明されたほうがよいと思います。 上記の説明を拝見するとArrayListの内部のテーブルサイズとHashMapの内部のテーブルサイズを同列のものとして捉えておられるような印象があります。そのためハッシュ法というのがどういうものなのかを理解されていないようにも見えてしまいます。ハッシュ法ではキーの衝突をなるべくさけるためある程度の空きがある状態で使うのが普通ですので。 例えばもしメモリー使用量を極力少なくしたいという場合ならハッシュ法を用いずに二分探索(あるいは容量が非常に少ないなら線形探索)するようなMapを使うという選択肢もあるかも知れません。ひょっとしたらそういうものを期待されているのでしょうか?

oooo111
質問者

補足

情報が少ない中でのご回答ありがとうございます。 アプリケーション起動時に設定ファイルの内容をHashMapに読み込み、以降はHashMapに対して、削除、追加、更新といったことを一切いたしません。 後は、値の参照だけですので、高速にアクセスできればよく(←このためハッシュを採用)、ハッシューキーの衝突等一切考慮する必要がありません。 ですので、パソコンで動くアプリですが、メモリ使用量を少しでも節約したく、質問ました。優先順位としては動作速度>メモリ使用率なもので。。。 1番 設定値に高速アクセスすること 2番 メモリ使用量が少ないほうがいい 何かいい方法があればいいなといった感じです。

全文を見る
すると、全ての回答が全文表示されます。
  • ninoue
  • ベストアンサー率52% (1288/2437)
回答No.1

Java Development Kitに同封されているソースを確認してみて下さい。 HashMap の登録Objectエントリ数に応じてHashTableのエントリ数は適当なタイミングで自動調整するようにコントロールされているので、通常の使用方法では容量の圧縮などを気にしないでも良いように調整されています。 殆ど空のHashTable Entryに有効Objectがパラパラと登録されている状態、 或いは複数の同一Hash値に多数のObjectが登録されている状態など、Hash値の種類不足状態、 等がObject登録中等に見つかると、Hash値等のTable再構成が自動的に行われるようです。 java\util\HashMap.java のソース中のresize()、DEFAULT_LOAD_FACTOR、DEFAULT_INITIAL_CAPACITY 等を確認してみて下さい。

oooo111
質問者

補足

情報が少ない中でのご回答ありがとうございます。 ソースはチラッと読みました。ご指摘どおり、値の更新などあったらハッシュテーブルのサイズが更新されていますが、なにぶん値の更新を一切おこなわないもので、何かいい方法があればいいなと思い質問いたしました。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • HashMapがおかしい

    HashMap で以下の様にコーディングしました。 当然 map の中には19個のオブジェクトが存在するはずですが、何故か15個しかありません。どなたか原因を御存知でしょうか? HashMap map = new HashMap(); map.put("key1", new Integer(1)); . (2->8)省略 . map.put("key9", new Integer(9)); map.put("key10", new String("10")); . (11->18)省略 . map.put("key19", new String("19")); 以下エクリプスのデバッガで取得したもの。 ECLIPSE 2.1.3 / JDK 1.4.2.03 map= HashMap (id=21) entrySet= HashMap$EntrySet (id=50) keySet= null loadFactor= 0.75 modCount= 19 size= 19 table= HashMap$Entry[32] (id=26) [0]= null [1]= HashMap$Entry (id=28) [2]= HashMap$Entry (id=31) [3]= null [4]= null [5]= null [6]= null [7]= null [8]= null [9]= HashMap$Entry (id=32) [10]= HashMap$Entry (id=33) [11]= null [12]= null [13]= HashMap$Entry (id=34) [14]= HashMap$Entry (id=35) [15]= HashMap$Entry (id=36) [16]= HashMap$Entry (id=37) [17]= null [18]= null [19]= null [20]= HashMap$Entry (id=38) [21]= null [22]= null [23]= HashMap$Entry (id=39) [24]= HashMap$Entry (id=40) [25]= null [26]= HashMap$Entry (id=41) [27]= HashMap$Entry (id=42) [28]= null [29]= HashMap$Entry (id=43) [30]= HashMap$Entry (id=44) [31]= null threshold= 24 values= null

    • ベストアンサー
    • Java
  • String配列とHashMap

    メソッドの引数の数がとても多いので、String配列かHashMapにまとめて、値を渡すことになりました。 どちらを使うかなのですが、私の記憶だとString配列とHashMapの違いを次のように認識してるのですが、調べても答えが見つかりません。合ってるか教えてください。 String配列は、インデックスを検索しつつ値を取得してるので、インデックスの大きい番号ほど、値取得時の処理に時間を使う。HashMapは、特別な検索方法(?)で検索してるので、値取得時の処理に、時間をかけずにすむ。 なので、メソッドの引数として使うのはHashMapの方がよい。 メソッドの引数という性格上、要素数を固定しなくてもいいHashMapの方が使いやすいと思ってるのですが、現場のリーダーさんの認識とずれちゃってます。説得したいので、この辺りのことが解説されているサイトがありましたら、合わせて教えていただけると嬉しいです。

    • ベストアンサー
    • Java
  • HashMapについて

    java初心者です。 HashMap oya= new HashMap(); HashMap child=null; child = new HashMap(); child.put("test1",Object1); child.put("test2",Object2); oya.put("Oya1",child); child = new HashMap(); child.put("test3",Object3); child.put("test4",Object4); child = new HashMap(); oya.put("Oya2",child); 上記のように値をセットした状態で ループの中でtest1の値を比較したいのです。 たとえば下記みたいに下記のやり方では出来なのは分かっています 値の比較の仕方を教えてください。 for(int i=0;oya.size();i++){ if(test1.equals("aaaa")){ bbb = "kkk"; break; } } よろしくお願いします。

    • ベストアンサー
    • Java
  • 大容量のファイルを圧縮出来る圧縮形式トについて

    大容量のファイルを圧縮できる形式(ソフト)を探しています。 ファイルの容量は約15GBくらいです。 これくらいのファイル容量を圧縮できる 圧縮形式をご存知の方 この圧縮形式だと圧縮できるファイルサイズは MAX○○GBまでみたいな情報を表示しているサイトをご存知の方 教えていただけないでしょうか? 圧縮できる最大容量という情報は意外に少なくて困っています ちなみに現在ファイルの分割は想定していません。

  • VectorとArrayListの違い

    お世話になっています。 VectorとArrayListやHashTableとHashMapなど、同期型と非同期型のクラスなどありますよね。 これらは具体的にどのようなときに使い分ければ良いのでしょうか? 私の考えでは、どの場面でもArrayListやHashMapを使っても問題ないと思ってしまいます。 マルチスレッドでスレッドが生成される前に生成されたListオブジェクトを参照した場合には予想と異なる動きをしそうですが、それ以外では全く問題ないように思います。 どの様に使い分ければよいのでしょうか?

    • ベストアンサー
    • Java
  • ArrayListからHashMapの変換

    質問1) ArrayListからHashMapの変換(処理要件は満たすが、より良い方法がないか) 質問2) より良い設計はどうするべきか ※ 長文です。すいません。 == 前提条件:  工程) 保守フェーズ  環境) 3階層のWebシステム(クライアント/AP/DB)、AP実行環境はJava(1.4)、DBはOracle(10g) 処理の目的:  DBに存在するレコードの一覧を画面に表示する。  ただし存在しないレコードはnull(空)表示する。 以下テーブルが存在します。 ----------テーブルイメージ---------------- 内部キー(ID)  表示順序   画面表示名 (以降のカラム省略) ---------------------------------------- 1         1        AAAAAA 2         3        CCCCCC 3         5        DDDDDDD ---------------------------------------- 画面表示は以下です。表示枠は5つ。その他の項目も存在する。 ------------画面表示イメージ-------------- 1: AAAAAA 2: (空) 3: CCCCCC 4: (空) 5: DDDDDDD ----------------------------------------- 現状: DB参照は内製のORマッパを使用します。その内のひとつ、メソッドAは 上記テーブルを対象に3つのDTO(Data Transfer Object)を保持したArrayListを返却します。(orderは内部キー) 一方、画面表示ではkey=Valueでの取扱いが有利なため、HashMapで組んでいます。 このため、新たに構築したHashMapにArrayListの内容を順次展開しながら、Mapに 詰めなおすロジックが必要となっています。 (擬似コード)------ List list = ORマッパ.メソッドA(); Map map = new HashMap(); int order = 0; int listIndex = 0; DTO dto = null; for (int i = 0; i < DISPLAY_MAX_COUNT; i++) {   dto = (DTO)list.get(listIndex);   order = dto.get表示順序();   if (i == order) {     map.put((String)i, dto);      listIndex++;    } else {     map.put((String)i, null);   } } (擬似コード)------ 以上を踏まえ、質問いたします。 質問1) ロジックに対するInput/Outputを変更しない前提で、 ArrayListからHashMapの変換でよりよい方法はないか。 質問2) 仮に設計や製造を一からやりなおすことができるとしたら、 より良い設計はどうするべきか。 長文申し訳ないです。最後まで目を通していただきありがとうございます。

  • ArrayListとHashMapを利用する問題について

    『問題』 (1)ArrayListのオブジェクトを生成する。 (2)「何回入力しますか?」と出力し、入力処理を行う。 (3)(2)で入力された回数分、以下の処理を行う。   1)HashMapのオブジェクトを生成する。   2)「名前を入力して下さい。」と出力し、入力処理を行う。 3)「性別を入力して下さい。」と出力し、入力処理を行う。   4)「性別を入力して下さい。」と出力し、入力処理を行う。 5) 1)で作成したHashMapに、それぞれ入力された 名前・年齢・性別を設定する。   6)値を設定したHashMapを(1)で作成したArrayListへ格納する。 (4)ArrayListの件数分、以下の処理を行う。   1)ArrayListより、HashMapを取得する。   2)取得したHashMapより、それぞれ設定されている 名前・年齢・性別を取得する。   3)HashMapより取得した名前・年齢・性別を出力する。 『実行結果』 何回入力しますか? 2 名前を入力して下さい。 iwata 年齢を入力して下さい。 27 性別を入力して下さい。 men 名前を入力して下さい。 hana 年齢を入力して下さい。 21 性別を入力して下さい。 women 名前=iwata 年齢=27 性別=men 名前=hana 年齢=21 性別=women 上記のようなプログラムを書く問題について質問します。 (3)までは自力で書けて実行結果もこの通りになったのですが、 (4)が分からずに、実行結果では値の部分がnullと出力されて しまいました。自分でもこの記述は間違っているというのは感じる のですが、どうしたら値がちゃんと格納されるのか分かりません。 「ArrayListより、HashMapを取得する。」←特にこの部分を どう記述してよいのか・・・ 分かる方、上記の部分の記述方法だけでも構わないので教えて下さい。 『自分で書いたプログラム』 import java.util.*; import java.io.*; public class Sample02{ public static void main(String[] args)throws IOException{ ArrayList list = new ArrayList(); System.out.println("何回で入力しますか?"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str = br.readLine(); int num = Integer.parseInt(str); for(int i=0; i<num; i++){ HashMap map = new HashMap(); System.out.println("名前を入力して下さい。"); String name = br.readLine(); System.out.println("年齢を入力して下さい。"); String age = br.readLine(); System.out.println("性別を入力して下さい。"); String sex= br.readLine(); map.put("名前", name); map.put("年齢",age); map.put("性別",sex); list.add(name); list.add(age); list.add(sex); } for(int i=0; i<num; i++){ HashMap map = new HashMap(); String name = (String)map.get("名前"); String age = (String)map.get("年齢"); String sex = (String)map.get("性別"); System.out.println("名前=" + name); System.out.println("年齢=" + age); System.out.println("性別=" + sex); } } }

    • ベストアンサー
    • Java
  • 圧縮すると容量が増える。

    動画ファイル(200MB前後@avi)をrarやzipや7zその他いろいろな圧縮方法で圧縮するとなぜか容量が増えています。 WinRAR,7-zip,+Lhaca,Lhaplusなどのソフト試しましたがすべて結果は容量が増えていました。 ■質問内容 なぜ圧縮しているにもかかわらず容量が増えるのか。 わかる方お願いします。 多少詳しい説明、専門的な用語が入ってもかまいません。

  • 圧縮したが容量変わらず

    +Lhaca Ver.0.72というソフトでソフトを圧縮しました。圧縮されたファイルの拡張子はlzhです。どれくらい容量が小さくなったか調べてみると・・・同じです!いったいどういうことなのでしょうか。アイコンの形も変わったのに。ちなみに、元のファイルの拡張子はmifです。 原因と正しい圧縮方法を教えて下さい。宜しくお願いします

  • 何とか500KBまで容量を圧縮したいのですが、もうお手上げです。

    携帯での動画閲覧のために、ぜひ画像サイズ176×144 で容量圧縮したいのですが出来ないでしょうか? 携帯動画変換君では画像サイズ240×176 が最高で2.73MBのavi形式の動画ファイルが、519KBまで圧縮することができましたが、 何とか500KBまで容量を圧縮したいのですが、もうお手上げです。 詳しい方おられましたらぜひ助けてください<(_ _)>