Перечисление, реализующее черты — проблемы с памятью?

#java #groovy #memory-leaks #traits #dry

#java #groovy #утечки памяти #Трейты #сухой

Вопрос:

Я пытаюсь ВЫСУШИТЬ свой код, и я впервые использовал для этого, traits чтобы улучшить свой enums .

Что я хочу сделать, так это: для заданного массива строк найдите все перечисления, соответствующие хотя бы одному ключевому слову (без учета регистра)

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

Вот запись из VisualVM примерно через 10 минут выполнения, столбец «Живые объекты» всегда увеличивается после каждого снимка, а количество элементов по сравнению со второй строкой настолько велико… визуальное профилирование виртуальной машины

Мой размер кучи тоже всегда увеличивается… визуальная куча виртуальной машины

Черта :

 trait BasedOnCategories {
    String[] categories
    
    static getSymbolFromIndustries(Collection<String> candidates) {
        values().findAll {
            value -> !value.categories.findAll {
                categorie -> candidates.any {
                    candidate -> categorie.equalsIgnoreCase(candidate)
                }
            }
            .unique()
            .isEmpty()
        }
    }
}
  

Одно из нескольких перечислений, которые у меня есть, реализует trait

 enum KTC implements BasedOnCategories, BasedOnValues {
    KTC_01([
            'industries': ['Artificial Intelligence','Machine Learning','Intelligent Systems','Natural Language Processing','Predictive Analytics','Google Glass','Image Recognition', 'Apps' ],
            'keywords': ['AI','Voice recognition']
    ]),
    // ... more values
    KTC_43 ([
            'industries': ['Fuel','Oil and Gas','Fossil Fuels'],
            'keywords': ['Petroleum','Oil','Petrochemicals','Hydrocarbon','Refining']
    ]),
    // ... more values
    KTC_60([
            'industries': ['App Discovery','Apps','Consumer Applications','Enterprise Applications','Mobile Apps','Reading Apps','Web Apps','App Marketing','Application Performance Management', 'Apps' ],
            'keywords': ['App','Application']
    ])

    KTC(value) {
        this.categories = value.industries
        this.keywords = value.keywords
    }
  

Мои тесты, основанные на данных

     def "GetKTCsFromIndustries"(Collection<String> actual, Enum[] expected) {
        expect:
        assert expected == KTC.getSymbolFromIndustries(actual)

        where:
        actual                                              | expected
        [ 'Oil and Gas' ]                                   | [KTC.KTC_43]
        [ 'oil and gas' ]                                   | [KTC.KTC_43]
        [ 'oil and gas', 'Fossil Fuels' ]                   | [KTC.KTC_43]
        [ 'oil and gas', 'Natural Language Processing' ]    | [KTC.KTC_01, KTC.KTC_43]
        [ 'apps' ]                                          | [KTC.KTC_01, KTC.KTC_60]
        [ 'xyo' ]                                           | []
    }
  

Мои вопросы :

  • Если у кого-то есть какие-то подсказки, которые помогут мне исправить эти утечки…
  • Есть ли более элегантный способ написания getSymbolFromIndustries метода?

Спасибо.

Ответ №1:

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

https://groovyconsole.appspot.com/script/5205045624700928

 trait BasedOnCategories {

    Set<String> categories
    
    void setCategories( Collection<String> cats ) {
        categories = new HashSet( cats*.toLowerCase() ).asImmutable()
    }

    @groovy.transform.Memoized
    static getSymbolFromIndustries(Collection<String> candidates) {
        def lowers = candidates*.toLowerCase()
        values().findAll{ value -> !lowers.disjoint( value.categories ) }
    }
}
  

Теперь остальная часть контекста

 trait BasedOnValues {
    Set<String> keywords
}

enum KTC implements BasedOnCategories, BasedOnValues  {
    KTC_01([
            'industries': ['Artificial Intelligence','Machine Learning','Intelligent Systems','Natural Language Processing','Predictive Analytics','Google Glass','Image Recognition'],
            'keywords': ['AI','Voice recognition']
    ]),
    // ... more values
    KTC_43 ([
            'industries': ['Fuel','Oil and Gas','Fossil Fuels'],
            'keywords': ['Petroleum','Oil','Petrochemicals','Hydrocarbon','Refining']
    ]),
    // ... more values
    KTC_60([
            'industries': ['App Discovery','Apps','Consumer Applications','Enterprise Applications','Mobile Apps','Reading Apps','Web Apps','App Marketing','Application Performance Management'],
            'keywords': ['App','Application']
    ])

    KTC(value) {
        this.categories = value.industries
        this.keywords = value.keywords
    }
}

// some tests

[
    [ [ 'Oil and Gas' ], [KTC.KTC_43] ],
    [ [ 'oil and gas' ], [KTC.KTC_43] ],
    [ [ 'oil and gas', 'Fossil Fuels' ], [KTC.KTC_43] ],
    [ [ 'oil and gas', 'Natural Language Processing' ], [KTC.KTC_01, KTC.KTC_43] ],
    [ [ 'xyo' ], [] ],
].each{
    assert KTC.getSymbolFromIndustries( it[ 0 ] ) == it[ 1 ]
}
  

а затем измерьте производительность

Комментарии:

1. Мне нравится, как вы очищаете trait ! Я никогда не думал о @Memoized nor a Set в groovy, но я делаю это каждый раз в node / react ^^ спасибо за это уже! Я проведу тест как можно скорее, и я прокомментирую / одобрю ваше решение после результатов;) большое спасибо, что нашли время для просмотра моего кода 🙂

2. добавлено disjoint , чтобы сделать код еще проще. Кстати, в react я использую приемы, которые я узнал от groovy 😉

3. Это правда, es6 и groovy у них много общего! : D Первые результаты теста кажутся лучше, Live Objects часто очищаются, Allocated Object все еще растут, я дважды проверю, как я использую метод, если я забыл какие-либо «мертвые ссылки»