Утечка памяти в строке Java - PullRequest
7 голосов
/ 20 мая 2011

Я не эксперт по Java.

Мой код читает файл в String. Этот код выполняется каждые 5 минут. Размер файла варьируется. Иногда это 100, иногда 1000 строк.

У меня нехватка памяти, через несколько дней.

У меня вопрос: когда мой код выходит за рамки Reading file function, собирает ли Java-мусор строку?

Я очень запутался, читая в Интернете Некоторые люди говорят, что он не удаляется и использует StringBuffer.

// Demonstrate FileReader.

import java.io.*;
class FileReaderDemo {
    public static void read(BufferedReader br) throws Exception {
        long length = 0;
        String s;
        while (true) {
            s = br.readLine();
            s += "abcd";
            if (s == null) {
                break;
            }
            length += s.length();
            //System.out.println(s);
        }
        System.out.println("Read: " + (length / 1024 / 1024) + " MB");
    }

    public static void main(String args[]) throws Exception {
        //FileReader fr = new FileReader("FileReaderDemo.java");
        FileReader fr = new FileReader("big_file.txt.1");
        BufferedReader br = new BufferedReader(fr);
        String s;
        read(br);
        fr = new FileReader("big_file.txt.1");
        br = new BufferedReader(fr);
        read(br);
        fr = new FileReader("big_file.txt.1");
        br = new BufferedReader(fr);
        read(br);
        fr = new FileReader("big_file.txt.1");
        br = new BufferedReader(fr);
        read(br);
        BufferedReader in = new BufferedReader(new InputStreamReader(System. in )); in .readLine();
        fr.close();
    }
}

Ответы [ 5 ]

6 голосов
/ 20 мая 2011

Здравствуйте, я не эксперт по Java.

У каждого есть что-то, чему он может научиться.

Мой код читает файл в строку,код выполняется каждые 5 минут.Сейчас иногда размер файла 100 строк, иногда 1000 строк.

Звучит не очень много или очень часто.Не должно быть проблем.

У меня нехватка памяти, через несколько дней.

Вы должны быть в состоянии получить дамп кучи и посмотреть, где у вас естьне хватает памяти и почему.

Вопрос, который у меня возникает, - когда мои коды выходят за рамки функции чтения файла.Собирает ли Java-мусор строку.

Его можно собирать, когда он больше недоступен по ссылке Strong.

Я довольно сбит с толку, читая в Интернете некоторые высказыванияон не удаляется и использует StringBuffer

Похоже, вы попали в нужное место.Я никогда этого не слышал.

5 голосов
/ 20 мая 2011

Ваш read метод никогда не прекратит работу.Достигнув конца файла, вы просто продолжаете добавлять строку "nullabcd" к s навсегда.

РЕДАКТИРОВАТЬ: забудьте, что s назначается каждый раз заново.Тем не менее, я не вижу, как ваш read метод может завершиться.

3 голосов
/ 20 мая 2011

Код, который вы опубликовали, не пропустит память.Однако цикл while (true) никогда не прекратится, потому что s никогда не будет null в момент, когда вы его тестируете.


Позволяет немного изменить его, чтобы он работал "

    public static void read(BufferedReader br) throws Exception {
            long length = 0;
            String s = "";
            while (true) {
                    String ss = br.readLine();
                    if (ss == null) {
                            break;
                    }
                    s += ss;
                    length += ss.length();
            }
            System.out.println("Read: " + (length/1024/1024) + " MB");
    }

Этот код также не пропускает память, поскольку все строки, созданные в методе, будут кандидатами на сборку мусора при возврате метода (если не раньше).

Каждый раз, когда мы выполняем s += ss; создается новая строка, состоящая из всех символов, находящихся в настоящее время в s, и символов в ss.Предполагая, что имеется N строк, содержащих в среднем L символов, оператор s += ss; будет вызван N раз, создаст N строк и скопирует в среднем (N * L)^2 / 2 символов.


Тем не менее, является хорошей причиной для создания StringBuilder, то есть для уменьшения количества выделения строк и продолжения копирования символов.Давайте перепишем метод, чтобы использовать StringBuilder;то есть замена StringBuffer, который не синхронизирован.

    public static void read(BufferedReader br) throws Exception {
            long length = 0;
            StringBuilder sb = new StringBuilder(sb);
            while (true) {
                    String ss = br.readLine();
                    if (ss == null) {
                            break;
                    }
                    sb.append(ss);
                    length += ss.length();
            }
            System.out.println("Read: " + (length/1024/1024) + " MB");
    }

Эта версия перераспределяет внутренний массив символов StringBuilder самое большее log2(N) раз и копирует самое большее 2 * N * L символов.


Резюме - использование StringBuilder - хорошая идея, но не из-за утечек памяти.Если у вас есть утечка памяти, ее нет в исходном примере кода или в фиксированной версии.

2 голосов
/ 20 мая 2011

изменить программу, как показано ниже, чтобы использовать меньше памяти. Огромный источник потребления памяти связан с вашей повторной конкатенацией строк s += "abcd"; - избегайте этого, и вы, вероятно, более чем вдвое уменьшите потребление памяти (не проверено - профилируйте его самостоятельно, если хотите знать).

public static void read(BufferedReader br) throws Exception {

    long length = 0;
    //String s; <--- change to the line below
    StringBuilder sb = new StringBuilder();
    while (true) {
        String s = br.readLine();
        if (s == null) {
            break;
        }
        //s += "abcd";  <--- change to the line below
        sb.append(s).append("abcd");
        length += s.length();
        //System.out.println(s);
    }
    System.out.println("Read: " + (length / 1024 / 1024) + " MB");
}
1 голос
/ 20 мая 2011

Как отмечают другие, этот код никогда не заканчивается.Похоже, что отправленный вами код не является исходным кодом, с которым у вас проблемы.

Трудно диагностировать, не видя фактический код, но строки определенно будут собираться мусором, если их не будетссылается из других частей кода.

Дикий догадка: вы вызываете close() для ваших Readers и InputStreams, как только вы закончите с ними?В противном случае это может быть причиной ошибки нехватки памяти.

...