String.replace 上的 java.lang.OutOfMemoryError

标签 java android out-of-memory

我有一个包含 234 行 string1@string2@string3 的文本文件。

kya@きゃ@キャ
kyu@きゅ@キュ
kyo@きょ@キョ
sha@しゃ@シャ
shu@しゅ@シュ
...so 234 lines

我正在编写转换器,将带有 string2 或 string3 的单词转换为带有 string1 的单词。

InputStream is = context.getResources().openRawResource(R.raw.kanatoromaji);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr);
String line;
try {
    while ((line = reader.readLine()) != null) {
        String[] parts = line.split("@");
        String romaji = parts[0];
        String hiragana=parts[1];
        String katakana = parts[2];

        if (hiragana!=null&&word.contains(hiragana)) {
                word = word.replace(hiragana, romaji);//in this line getting outOfMemory error
        }
        if (word.contains(katakana)) {
            word = word.replace(katakana, romaji);
        }
    }

} catch (IOException e) {
    e.printStackTrace();
}

我多次调用此方法(一次运行 200k-300k 次)。所以这导致了这个错误: 07-24 00:52:32.859 10848-10848/net.joerichard.test E/AndroidRuntime:致命

EXCEPTION: main
    java.lang.OutOfMemoryError
            at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:94)
            at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:132)
            at java.lang.StringBuilder.append(StringBuilder.java:124)
            at java.lang.String.replace(String.java:1367)
            at net.joerichard.test.Converter.kanaToRomaji(Converter.java:32)
            at net.joerichard.test.MainActivity.migrateKanaKanji(MainActivity.java:222)
            at net.joerichard.test.MainActivity.access$700(MainActivity.java:29)
            at net.joerichard.test.MainActivity$10.onClick(MainActivity.java:131)
            at android.view.View.performClick(View.java:4240)
            at android.view.View$PerformClick.run(View.java:17721)
            at android.os.Handler.handleCallback(Handler.java:730)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5103)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
            at dalvik.system.NativeStart.main(Native Method)

我的代码有什么问题?如何解决?

更新:

根据JFPicard的回答,我将我的String word转换为StringBuilder sbWord。然后我尝试使用 StringBuilder 替换 string2 和 string3。我以前从未更换过 StringBuilder。我在 Google 中搜索并找到了这个 solution替换我的 StringBuilder 部件。现在我的代码如下所示:

public static String kanaToRomaji(Context context, String word) {

    String kana = word;
    StringBuilder sbWord = new StringBuilder(word);

    InputStream is = context.getResources().openRawResource(R.raw.kanatoromaji);
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader reader = new BufferedReader(isr);
    String line;
    try {
        while ((line = reader.readLine()) != null) {
            String[] parts = line.split("@");
            String romaji = parts[0];
            String hiragana=parts[1];
            String katakana = parts[2];

            if (hiragana!=null&&word.contains(hiragana)) {
                sbWord = replaceAll(sbWord, hiragana, romaji);//in this line getting outOfMemory error
            }
            if (word.contains(katakana)) {
                sbWord = replaceAll(sbWord, katakana, romaji);
            }
        }

    }
    catch (IOException e) {
        e.printStackTrace();
    }

    char[] chars = kana.toCharArray();
    for (char character: chars)
    {
        if(sbWord.toString().contains(String.valueOf(character)))
        {
            new MyLog(kana+":"+sbWord.toString());
            break;
        }
    }

    return word;
}

替换 StringBuilder 部分的方法:

public static StringBuilder replaceAll(StringBuilder builder, String from, String to)
{
    int index = builder.indexOf(from);
    while (index != -1)
    {
        builder.replace(index, index + from.length(), to);
        index += to.length(); // Move to the end of the replacement
        index = builder.indexOf(from, index);
    }
    return builder;
}

现在我收到这个错误: 07-24 01:23:52.890 13512-13512/net.joerichard.test E/AndroidRuntime:致命

EXCEPTION: main java.lang.OutOfMemoryError at java.lang.AbstractStringBuilder.move(AbstractStringBuilder.java:397) at java.lang.AbstractStringBuilder.insert0(AbstractStringBuilder.java:356) at java.lang.AbstractStringBuilder.replace0(AbstractStringBuilder.java:442) at java.lang.StringBuilder.replace(StringBuilder.java:637) at net.joerichard.test.Converter.replaceAll(Converter.java:65) at net.joerichard.test.Converter.kanaToRomaji(Converter.java:33) at net.joerichard.test.MainActivity.migrateKanaKanji(MainActivity.java:222) at net.joerichard.test.MainActivity.access$700(MainActivity.java:29) at net.joerichard.test.MainActivity$10.onClick(MainActivity.java:131) at android.view.View.performClick(View.java:4240) at android.view.View$PerformClick.run(View.java:17721) at android.os.Handler.handleCallback(Handler.java:730) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5103) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:525) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method)

遇到这种情况怎么办?

最佳答案

我想我有一个想法。

这一行 word = word.replace(hiragana, romaji);

还有这个 word = word.replace(katakana, romaji);

每次创建一个新的字符串。 String 是不可变的,因此它会消耗内存。你的情况很多。

尝试改用 StringBuilder。

关于String.replace 上的 java.lang.OutOfMemoryError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31596991/

相关文章:

java - 在内存中存储大量 IP 地址

java - 在shell中启动java程序但用eclipse编写?

java - 从通配符到正则表达式

javascript - 在 javascript 中访问/生成 java 枚举

android - 绑定(bind)服务 vs 未绑定(bind) + 单例通信

glassfish 中的 Java 堆空间错误

java - 在 Android CallLogCalls 中使用 PHONE_ACCOUNT_ID 识别 SIM 卡插槽

android - 从摩托罗拉 Razr Android 4.0.4 上的耳机捕获媒体按钮

android - 横幅 - 是否有内置 View ?

java - 异常: java. lang.OutOfMemoryError,无法创建新的 native 线程