0

Java String は不変であるため、

文字列を作成すると、メモリ ブロックがヒープに割り当てられます。その値を変更すると、その文字列用に新しいメモリ ブロックが作成され、古いメモリ ブロックがガベージ コレクションの対象になります。たとえば、

String str = func1_return_big_string_1()"; //not literal
String str= func2_return_big_string_2()"; //not literal

しかし、ガベージ コレクションが開始されるまでに時間がかかるため、大きな文字列 1 と 2 の両方を含むヒープに実質的にメモリがあります。これが頻繁に発生すると、問題になる可能性があります。

大きな文字列 2 を文字列 1 のメモリ内の同じ場所を使用するようにする方法はありますか? 大きな文字列 2 を str に割り当てるときに余分なスペースを必要としません。

編集:すべての入力に感謝します。最終的に、JavaコードがC ++コードのように動作することを期待すべきではないことに気付きました(つまり、異なるメモリフットプリント)。期待どおりに動作する C++ 11 デモを作成しました。最大のメモリ フットプリントは約 20M (ロードしようとしていた最大のファイル) で、右辺値参照と移動代入演算子はすべて期待どおりに作動します。以下のデモは、VS2012 で c++ 11 を使用して行われました。

#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <thread>
using namespace std;

string readFile(const string &fileName)
{
    ifstream ifs(fileName.c_str(), ios::in | ios::binary | ios::ate);

    ifstream::pos_type fileSize = ifs.tellg();
    ifs.seekg(0, ios::beg);

    vector<char> bytes(fileSize);
    ifs.read(&bytes[0], fileSize);

    return string(&bytes[0], fileSize);
}

class test{
public:
    string m_content;
};

int _tmain(int argc, _TCHAR* argv[])
{
    string base("c:\\data");
    string ext(".bin");
    string filename;
    test t;
    //std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    cout << "about to start" << endl;
    for(int i=0; i<=50; ++i) {
        cout << i << endl;
        filename = base + std::to_string(i) + ext;
        //rvalue reference & move assignment operator here
        //so no unnecessary copy at all
        t.m_content = readFile(filename);
        cout << "szie of content" << t.m_content.length() << endl;
    }
    cout << "end" << endl;
    system("pause");
    return 0;
}
4

5 に答える 5

2

いくつかのオプションが表示されます。

  1. を使用しchar[]ます。
  2. 公開されている再利用可能なバッファを使用StringBuilderしてバージョンにコピーします。MyStringBuilder主な欠点は、正規表現がないことです。それが、パフォーマンスを向上させる必要があるときに私が行ったことです。
  3. JDK <=6 のハック: 文字列を再利用/文字バッファーをラップする保護されたコンストラクターがあります。JDK 7+ にはもうありません。これには非常に注意する必要があり、C/C++ のバックグラウンドがあれば問題ありません。
  4. 公開されている再利用可能なバッファにコピーStringします。MutableString利用可能なカスタム正規表現マッチャーがたくさんあるので、それらを追加しても問題はないと思います。
于 2013-10-20T21:05:29.377 に答える
2

StringBuffer、StringBuffer.append() を使用する

于 2013-10-20T16:20:06.803 に答える
1

インターンされていない文字列の場合は、それほど重要ではありません。メモリが不足し始めると、ガベージ コレクターは、参照されなくなったオブジェクトをすべて削除します。

詳細については、文字列リテラルのガベージ コレクションを参照してください。

EDIT非インターン文字列は、通常のオブジェクトと同じです。それへの参照がなくなると、ガベージ コレクションが行われます。

元の文字列を指してstrいる唯一の参照が残っていて、別のstrものを指すように変更されている場合、元の文字列はガベージ コレクションの対象となります。メモリが必要な場合は JVM がメモリを収集するため、メモリ不足を心配する必要はありません。

于 2013-10-20T16:24:29.397 に答える
1

MutableStringの実装を見つけました。Maven Centralで利用できます。以下は、彼らの JavaDoc ページからの抜粋です。

  • 変更可能な文字列はほとんどスペースを占有しません。それらの唯一の属性は、バッキング文字配列と整数です。
  • それらのメソッドは可能な限り効率的であるように努めます。たとえば、配列アクセスの制限によってパラメーターの制限が暗示される場合、明示的にチェックせず、ブルーム フィルターを使用して複数文字の置換を高速化します。
  • バッキングアレイに直接アクセスできます(自己責任で)。
  • CharSequence,たとえば、標準の Java API を使用して、可変文字列を正規表現と照合または分割できるように実装します。
  • を実装しているため、および類似のクラスAppendableで使用できます。Formatter

アップデート

Appendableこのインターフェイスを利用MutableStringして、メモリ オーバーヘッドがほぼゼロ (Java のデフォルトのバッファ サイズである 8KB) でファイルを読み取ることができます。Guava のCharStreams.copyを使用すると、次のようになります。

MutableString str = new MutableString((int) file.length());
CharStreams.copy(Files.newReaderSupplier(file, Charset.defaultCharset()), str);
System.out.println(str);

完全な作業例

于 2013-10-21T13:11:52.363 に答える