уменьшить сборку мусора Java для методов, возвращающих массивы? - PullRequest
0 голосов
/ 26 октября 2018

Объект A имеет метод B () и живет большую часть жизни приложения. B вызывает объект C методом D (). D () возвращает массив, содержащий до x объектов MyData. MyData может быть POD (обычные старые данные) / PDS (пассивная структура данных) или может быть иным, но MyData можно использовать повторно, вызывая методы или устанавливая поля; его индивидуальность или функциональность не отлиты в камне во время строительства или иным образом.

В настоящее время B () определяется как:

class A {
  public B() {
    MyData[] amydata = c.D( 5 );
       :
       :
  }
}

В настоящее время D () определяется как:

MyData[] D( int iRows ) {

    MyData[] amydata = new MyData[ iRows ];

    for ( int i = 0; i < iRows; i++ ) {

        if ( no more data )
            return amydata;

        amydata [ i ] = new MyData();

        // calculate or fill in MyData structure.
    }

    return amydata;
}

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

Так что, если у меня есть проход вызывающей стороны в ссылке на массив:

class A {
  int iRequestSize = 5;
  int iResultSize;
  MyData[] amydata = new MyData[ iRequestSize ];

  public B() {
    iResultSize = c.D( iRequestSize, amydata );
       :
       :
    // use up to iResultSize even though array is potentially bigger.
  }
}

// returns number of rows actually used
int D( int iRowsMax, MyData[] amydata ) {

    for ( int i = 0; i < iRowsMax; i++ ) {

        if ( no more data )
            return i;

        if ( amydata [ i ] == null )
            amydata [ i ] = new MyData();

        // calculate or fill in MyData structure.
    }

    return iRowsMax;
}

Я - пользователь C ++ и новичок в Java, но, похоже, если предположить, что MyData может быть переработана таким образом, вторая версия должна избегать создания и копирования MyData, а также устранения сбора мусора?

Ответы [ 2 ]

0 голосов
/ 27 октября 2018

Отказ от ответственности: Читая комментарии ОП, я должен признать, что у меня не было его реального намерения, то есть разработать приложение в реальном времени, избегая сбора мусора настолько, насколько это возможно. возможно, очень особенная и редкая ситуация в мире Java.

Таким образом, следующий ответ не соответствует его проблеме. Но поскольку случайный читатель, мигрирующий с C ++ на Java, может наткнуться на этот вопрос и ответ, он / она может получить некоторые полезные советы о типичном стиле программирования Java.


Несмотря на то, что синтаксис Java и C ++ имеет некоторые сходства, из-за очень разных сред выполнения вы должны использовать другой стиль кодирования.

Будучи парнем из Java на протяжении десятилетий, я бы наверняка предпочел оригинальную сигнатуру метода. Как вызывающий метод D(), зачем мне создавать структуру данных результатов, а не получать ее из метода, который я вызываю? Это переворачивает естественный поток данных.

Я знаю, что в старые добрые времена C, когда динамическое управление памятью означало много головной боли, было очень распространено подготавливать массив результатов вне функции и использовать функцию только для заполнения результатов, как вы писали вторую версию. , Но забудьте об этом с Java и просто позвольте сборщику мусора выполнить свою работу (и он очень хорош в этой работе). Обычно попытка «помочь» GC приводит к коду, который на самом деле менее эффективен и труднее для чтения. И если вы действительно хотите придерживаться этого стиля, нет необходимости передавать как максимальное количество строк, так и массив, так как сам массив знает его длину (это отличается от массивов C старого стиля), давая максимальное число строк.

Вы предполагаете

вторая версия не должна создавать и копировать MyData

Это звучит как неправильное представление о внутренней работе Java. Каждый раз, когда вы выполняете выражение new MyData(...), вы создаете новый экземпляр где-то в куче. Предоставление массива MyData[] не избежит этого. В переводе на терминологию C массив просто содержит указатели на MyData объектов, а не на реальные объекты. И экземпляры Java почти никогда не копируются (если вы явно не вызываете что-то вроде object.clone()). Это просто ссылка (= указатель) на экземпляр, который копируется при назначении чего-либо переменной.

Но даже первая версия далека от совершенства, если я правильно понимаю ее назначение. Сам метод D() может определить, когда больше нет доступных данных, так почему он должен возвращать массив дольше, чем необходимо? С массивами Java это немного неудобно, поэтому типичный код Java возвращает List<MyData> в подобных ситуациях.

Еще один комментарий к конструктору MyData(), а затем «вычислить или заполнить структуру MyData». Я знаю, что стиль существует (и довольно популярен в семействе языков C), но он не преобладает в Java, и мне это особенно не нравится. Для меня это звучит как спросить «Дай мне машину» и получить просто скелет вместо годной к употреблению машины. Если я хочу, чтобы у него были колеса, двигатель и сиденья, я позже должен был сам их поставить. Если пригодный для использования автомобиль нуждается в выборе опций, я хочу предоставить их при заказе автомобиля / вызове конструктора, чтобы я мог честно назвать результат автомобилем вместо скелета.

И, наконец, комментарий к соглашениям об именах Java: подавляющее большинство кода Java следует соглашениям, поэтому имена ваших методов, начинающиеся с верхнего регистра, выглядят для меня очень странно.

0 голосов
/ 27 октября 2018

Я бы сказал, что второй вариант хуже.

В первом варианте amydata и все объекты, на которые он ссылается, могут быть удалены сборщиком мусора, как только выйдет метод B() (при условии, что B не хранит ссылку на amydata где-то еще.)

Во втором варианте amydata нельзя собирать мусор, пока существует экземпляр A.

Рассмотрим случай, когда при первом вызове D() он возвращает 5 ссылок на объекты MyData, но при последующих вызовах он не возвращает больше строк. В первом варианте массив amydata и 5 объектов MyData, на которые ссылаются, могут быть собраны сборщиком мусора, как только B() вернется. Но во втором варианте ни массив amydata, ни объекты 5 MyData, на которые он ссылается, не могут быть собраны сборщиком мусора - возможно, никогда в течение всего времени выполнения вашего приложения.

Помните: Java Garbage Collector оптимизирован для многих недолговечных объектов

...