2012-11-11 14 views
5

大規模なCSV形式のファイル(通常は200-600mb)をJavaで(効率的にメモリにアクセスし、できるだけ高速に)ロードしようとしています。現在、プログラムは文字列配列のリストを利用しています。この操作は以前は、各CSV行のテーブルと各「行」テーブルを保持するテーブルを使用するLuaプログラムで処理されていました。Java - 大量のString配列を効率的に格納する方法

以下

は、メモリの違いやロード時間の一例である:

  • CSVファイル - 232メガバイト
  • のLua - メモリ内の549メガバイト -
  • のJavaをロードするために157秒 - メモリ内の1378メガバイト - 12秒をロードする

正しく覚えていれば、実際の値への参照として、Luaテーブルの重複した項目が存在します。私は、Javaの例では、リストには各重複値の別々のコピーが保持されており、それはより大きなメモリ使用量に関連している可能性があると考えられます。以下

は、CSVファイル内のデータ上でいくつかの背景である。各列内
  • 特定のフィールドは、文字列(例えば、フィールドのセットの1つを含むことができる各フィールドは文字列で構成

    • 3とすることができます「赤」、「緑」、または「青」)。
    • コンテンツ内に個の重複文字列があります。があります。以下は

  • がロードされたデータを必要とすることができるもののいくつかの例です:指定した文字列と一致し、GUIに一致する文字列に
  • 表示の一致を返そうと、すべての文字列による

    • 検索テーブル(フィールドからソート可能)。
    • 文字列を変更または置き換えます。

    私の質問 - データを保持するのに必要なメモリは少なくても、データを簡単かつ迅速に検索/並べ替える機能はありますか?

  • +1

    あなたは、列3は、わずか数の可能な値を保持していることがわかっている場合、あなたは[インターンそれら](http://docs.oracleできました.com/javase/7/docs/api/java/lang/String.html#intern%28%29)を使用して、メモリ使用量を減らします。参考:http://stackoverflow.com/a/1855195/829571 – assylias

    +0

    ありがとうassylias私はそれを使用していくつかのテストを実行します。短い文字列には効率的かどうかは分かりますか? "To"または "Go"。ほとんどのフィールドには45文字+の文字列が含まれていますが、かなり短い文字列(4文字以下)もあります。 – user1816198

    +2

    http://stackoverflow.com/questions/12792942/alternatives-to-java-string-interningをご覧ください。 –

    答えて

    0

    たぶん、この記事では、いくつかの助けになることができます。ちょうどサイドノートとして

    http://www.javamex.com/tutorials/memory/string_saving_memory.shtml

    +0

    ありがとう - 非常に有用な情報。 – user1816198

    +1

    私は記事を介して提示された両方の例を試してみました。 intern()はほとんどのメモリを節約します。私は実験を続けるつもりです(特に私のプロジェクトをもっと終えた後)が、ロード時間がはるかに短くても、私のメモリ使用量はLuaに合っています。 – user1816198

    +0

    これは、あなたがリンクオンリーの回答をしてはならない理由です。リンクは現在死んでいます。 –

    0

    メモリの問題を最適化するには、Flyweightパターンを使用するようアドバイスしてください。特に、重複が多いフィールドの場合は注意してください。

    コレクションには、TreeSetまたはTreeMapを使用できます。あなたはLineItemクラスに良い実装を与える場合

    あなたはメモリが大量に使用する最適化することができます(equalshashcodeComparableを実施)。

    0

    DAWG

    Aは、非環式単語グラフは、(とにかくメモリ消費のための最良の)単語を格納するための最も効率的な方法で指示しました。

    しかし、おそらくここでは、重複していないと言っている人もいますが、同じインスタンスに対して複数の参照を行うだけです。

    +0

    ありがとう、私はこのオプションをもう少し調べます。残念なことはまだ考えていません。効率的なのはセッションごとにデータを読み込むことができるほど効率が高いことです。これはエンドユーザーにとっては優れています。 – user1816198

    0

    重複した文字列データについては、Java自体がすべての文字列が最終的なので気にする必要はなく、すべての参照がメモリ内の同じオブジェクトを対象とするため、心配する必要はありません。

    LUAは仕事をしていませんどのようにわからないが、Javaで、それはまた

    +0

    しかしこれが真であれば、equalsは全く必要ではなく、==は比較のために仕事をします – Igor

    +0

    これは正しい方法です、それはあなたがjavaのオブジェクトを比較する方法であるので、==でも動作しますが、 JVMが内部的に文字列を処理する方法による副作用 –

    +0

    文字列参照を保持するために内部的にJava VMのメモリ量がわかりませんが、十分な大きさのプログラムで==動作しないと確信しています – Igor

    1

    つの簡単な解決策は非常に効率的でなければなりません。あなたはすべてのユニークな文字列への参照を入れていたことがある場合は、HashMapを持つことができます。 ArrayListには、既存の一意の文字列への参照がHashMapにあります。

    ような何か:

    private HashMap<String, String> hashMap = new HashMap<String, String>(); 
    
    public String getUniqueString(String ns) { 
        String oldValue = hashMap.get(ns); 
        if (oldValue != null) { //I suppose there will be no null strings inside csv 
        return oldValue; 
        }   
        hashMap.put(ns, ns); 
        return ns; 
    } 
    

    簡単な利用法:

    List<String> s = Arrays.asList("Pera", "Zdera", "Pera", "Kobac", "Pera", "Zdera", "rus"); 
    List<String> finS = new ArrayList<String>(); 
    for (String er : s) { 
        String ns = a.getUniqueString(er); 
        finS.add(ns); 
    } 
    
    +0

    サウンドは、すでにjavaで最適化されたものを最適化しようとしているようです(メモリ内の文字列をメモリに保存する)。そのような実装は必要ありません。 –

    関連する問題