Возможная Утечка памяти в Количестве Загруженных классов в JAVA-приложении

Причина, по которой вы получаете эту ошибку, в том, что ваша функция registerKnownImplementations() не запускается.

Должна работать следующая суть: https://gist.github.com/dtartaglia/9f1f937628504ca56dbb1aac7d91df2b

Код также приведен ниже, но суть может быть обновлена: [ 115]

//
//  SKPhysicsWorld+Rx.swift
//
//  Created by Daniel Tartaglia on 21 Jan 2019.
//  Copyright © 2019 Daniel Tartaglia. MIT License.
//

import RxSwift
import SpriteKit

public
extension Reactive where Base: SKPhysicsWorld {

    var didBegin: Observable {
        return Observable.create { observer in
            physicsContatctDelegatesLock.lock(); defer { physicsContatctDelegatesLock.unlock() }
            let uuid = UUID()
            if let (delegate, beginners, enders) = physicsContatctDelegates[self.base] {
                var new = beginners
                new[uuid] = observer
                physicsContatctDelegates[self.base] = (delegate, new, enders)
            }
            else {
                let delegate = PhysicsContactDelegate(for: self.base)
                self.base.contactDelegate = delegate
                physicsContatctDelegates[self.base] = (delegate, [uuid: observer], [:])
            }

            return Disposables.create {
                physicsContatctDelegatesLock.lock(); defer { physicsContatctDelegatesLock.unlock() }
                let (delegate, beginners, enders) = physicsContatctDelegates[self.base]!
                var new = beginners
                new.removeValue(forKey: uuid)
                if new.isEmpty && enders.isEmpty {
                    physicsContatctDelegates.removeValue(forKey: self.base)
                }
                else {
                    physicsContatctDelegates[self.base] = (delegate, new, enders)
                }
            }
        }
    }

    var didEnd: Observable {
        return Observable.create { observer in
            physicsContatctDelegatesLock.lock(); defer { physicsContatctDelegatesLock.unlock() }
            let uuid = UUID()
            if let (delegate, beginners, enders) = physicsContatctDelegates[self.base] {
                var new = enders
                new[uuid] = observer
                physicsContatctDelegates[self.base] = (delegate, beginners, new)
            }
            else {
                let delegate = PhysicsContactDelegate(for: self.base)
                self.base.contactDelegate = delegate
                physicsContatctDelegates[self.base] = (delegate, [:], [uuid: observer])
            }

            return Disposables.create {
                physicsContatctDelegatesLock.lock(); defer { physicsContatctDelegatesLock.unlock() }
                let (delegate, beginners, enders) = physicsContatctDelegates[self.base]!
                var new = enders
                new.removeValue(forKey: uuid)
                if new.isEmpty && enders.isEmpty {
                    physicsContatctDelegates.removeValue(forKey: self.base)
                }
                else {
                    physicsContatctDelegates[self.base] = (delegate, beginners, new)
                }
            }
        }
    }
}

private
class PhysicsContactDelegate: NSObject, SKPhysicsContactDelegate {

    init(for world: SKPhysicsWorld) {
        self.world = world
        super.init()
    }

    func didBegin(_ contact: SKPhysicsContact) {
        physicsContatctDelegatesLock.lock(); defer { physicsContatctDelegatesLock.unlock() }
        let (_, beginners, _) = physicsContatctDelegates[world]!
        for each in beginners.values {
            each.onNext(contact)
        }
    }

    func didEnd(_ contact: SKPhysicsContact) {
        physicsContatctDelegatesLock.lock(); defer { physicsContatctDelegatesLock.unlock() }
        let (_, _, enders) = physicsContatctDelegates[world]!
        for each in enders.values {
            each.onNext(contact)
        }
    }

    let world: SKPhysicsWorld
}

private let physicsContatctDelegatesLock = NSRecursiveLock()
private var physicsContatctDelegates: [SKPhysicsWorld: (SKPhysicsContactDelegate, [UUID: AnyObserver], [UUID: AnyObserver])] = [:]

9
задан Kyle 3 October 2008 в 16:26
поделиться

6 ответов

Вы динамично создаете новые классы на лету так или иначе?

Спасибо за помощь. Я выяснил, какова проблема. В одном из моих классов я использовал Jaxb для создания строки XML. В выполнении этого, JAXB ueses отражение для создания нового класса.

JAXBContext context = JAXBContext.newInstance(this.getClass());

Таким образом, хотя JAXBContext не говорил вокруг в "куче", классы были загружены.

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

5
ответ дан 4 December 2019 в 13:06
поделиться

Я готов держать пари, что Ваша проблема связана с поколением байт-кода.

Многие библиотеки используют CGLib, BCEL, Javasist или Янино, чтобы генерировать байт-код для новых классов во времени выполнения и затем загрузить их из управляемого classloader. Единственный способ выпустить эти классы состоит в том, чтобы выпустить все ссылки на classloader.

Так как classloader сохранен каждым классом, это также означает, что Вы не должны выпускать ссылки на все классы также [1]. Можно поймать их с достойным профилировщиком (я использую Yourkit - ищут несколько classloader экземпляров с тем же сохраненным размером),

Одна выгода - то, что JVM не разгружает классы по умолчанию (причиной является назад совместимость - что люди предполагают (неправильно), что статические инициализаторы были бы выполнены только однажды. Истина - то, что они выполняются каждый раз, когда класс загружается.) Чтобы позволить разгрузиться, необходимо передать некоторое использование следующие опции:

-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled

(протестированный с JDK 1.5)

Даже затем чрезмерное поколение байт-кода не является хорошей идеей, таким образом, я предлагаю, чтобы Вы посмотрели в своем коде, чтобы найти преступника и кэшировать сгенерированные классы. Частые преступники являются языками сценариев, динамические прокси (включая тех сгенерированных серверами приложений) или огромная модель Hibernate (в этом случае, можно просто увеличить permgen).

См. также:

  1. http://blogs.oracle.com/watt/resource/jvm-options-list.html
  2. http://blogs.oracle.com/jonthecollector/entry/presenting_the_permanent_generation
  3. http://forums.sun.com/thread.jspa?messageID=2833028
4
ответ дан 4 December 2019 в 13:06
поделиться

Вы могли бы найти, что некоторые флаги горячей точки были полезны в понимании этого поведения как:

  • - XX: + TraceClassLoading
  • - XX: + TraceClassUnloading

Это - хорошая ссылка:

http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp

4
ответ дан 4 December 2019 в 13:06
поделиться

Если я не неправильно понимаю, мы здесь смотрим на загруженные классы, не экземпляры.

Когда Ваш код первые ссылки класс, JVM имеет ClassLoder, выходят и выбирают информацию о классе из .class файла и т.п.

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

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

Однако две вещи кажутся странными для меня:

  1. Почему это таким образом линейно?
  2. Почему это не выравнивается?

Я ожидал бы, что это отклонится вверх, но в шаткой строке, и затем сужаться на увеличении, поскольку JVM уже загрузила большинство классов Ваши ссылки программы. Я имею в виду, существует конечное число классов, на которые ссылаются в большинстве приложений.

Вы динамично создаете новые классы на лету так или иначе?

Я предложил бы запустить более простое тестовое приложение через тот же отладчик для получения базового случая. Затем Вы могли рассмотреть реализацию Вашего собственного ClassLoder, который выкладывает некоторую отладочную информацию, или возможно существует инструмент, чтобы заставить его сообщить.

Необходимо выяснить, каковы эти загружаемые классы.

3
ответ дан 4 December 2019 в 13:06
поделиться

Да, это обычно - утечка памяти (так как мы действительно не имеем дело с памятью непосредственно, это - больше утечки экземпляра класса). Я прошел этот процесс прежде, и обычно это - некоторый слушатель, добавил к старому инструментарию, который не удалил его сам.

В более старом коде отношения слушателя вызывают объект "слушателя" остаться вокруг. Я посмотрел бы на более старые инструментарии или, которые не были через многие версии. Любая длинно-существующая библиотека, работающая на более позднем JDK, знала бы о ссылочных объектах, который удаляет требование для, "Удаляют Слушателя".

Кроме того, вызов располагают на Ваших окнах, если Вы воссоздаете их каждый раз. Я не думаю, что они когда-либо уходят, если Вы не делаете (На самом деле существует также расположение на близкой установке).

Не волнуйтесь о Swing или слушателях JDK, они должны все использовать ссылки, таким образом, необходимо быть хорошо.

0
ответ дан 4 December 2019 в 13:06
поделиться

Используйте Память Eclipse Анализатор для проверки на дублированные классы и утечки памяти. Это могло бы произойти, что тот же класс загружается несколько раз.

С уважением, Markus

0
ответ дан 4 December 2019 в 13:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: