Я пытаюсь создать двухмерную платформенную игру с помощью SpriteKit. В игре 21 уровень, то есть 21 сцена и 21 тайлсет. Каждая сцена содержит несколько узлов тайлов, каждый из которых использует только 1 набор тайлов. В какой-то момент я обнаружил, что моя игра потребляет почти 2 ГБ памяти и иногда прерывается из-за проблем с памятью.
Я начал расследование причин этих утечек памяти с помощью инструментов. Я нашел 4 утечки, которые показаны на прикрепленном скриншоте. Ответственная библиотека — JavaScriptCore, я понятия не имею, что, черт возьми, это значит.
Итак, я продолжаю расследование и пытаюсь удалить блоки кода и ресурсы из проекта, чтобы понять, что происходит.
В конце мой проект содержал:
Код GameViewController:
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GKScene(fileNamed: "GameScene") {
if let sceneNode = scene.rootNode as! SKScene? {
sceneNode.scaleMode = .aspectFill
if let view = self.view as! SKView? {
view.presentScene(sceneNode)
view.ignoresSiblingOrder = true
}
}
}
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override var prefersStatusBarHidden: Bool {
return true
}
}
Таким образом, нет кода, который может вызвать утечку, и игра по-прежнему потребляет 2 ГБ в пиках. И только когда я удаляю из проекта все тайлсеты, кроме одного, который нужен для уровня - потребление памяти становится нормальным, около ~200мб.
Я предполагаю, что SpriteKit загружает все наборы тайлов в память, несмотря на то, что все узлы тайлов сцены используют только один набор тайлов.
Кроме того, игра работает хорошо, если я верну наборы тайлов в проект и удалю все узлы тайлов из сцены.
Мой вопрос в том, как правильно управлять этой ситуацией?
Спасибо!
Update1: график памяти прилагается Update2: предоставлен код GameViewController
Я тоже так сделал, график ничего полезного для меня не показывает. Скриншот графика прикрепил к сообщению.
Без кода ваш вопрос эквивалентен сопению. Мы не телепаты.
Вы должны освободиться от всех этих розово-фиолетовых "!". Иногда, например, пропустил weak. Иногда вы вызываете системную функцию несовершенным образом. Но сначала попробуйте убрать все эти !.
@Magnas Я обновляю пост с GameViewController, он действительно выглядит как GameViewController по умолчанию из игрового шаблона XCode SpriteKit.
@E.Coms Да, я знаю о сильных и слабых ссылках. Когда я попытался воспроизвести проблему, я удалил весь свой код из проекта и вместо этого вставил GameViewController по умолчанию из игрового шаблона XCode SpriteKit, чтобы показать, что в проекте нет кода, который может вызвать утечку памяти.
если это вызов системной функции, вы должны добавлять класс за классом и функцию за функцией, пока не увидите "!" выходит. Тогда вы будете знать, какой шаг представляет проблему.
@E.Coms Мне не нужно возвращать мой код обратно в проект, потому что утечка памяти происходит даже с GameViewController по умолчанию, который загружает мою сцену с тайловыми узлами. В проекте нет никакого другого кода, кроме GameViewController по умолчанию.
Вы знаете конкретную линию?
Вы можете добавить значение экземпляра для управления. Это означает извлечь локальную временную переменную, чтобы сохранить ее где-нибудь.
@E.Coms, к сожалению, утечки на графике не относятся к какой-либо строке кода или чему-то еще. :(
Не для графика. Просто удалите часть кода, а затем добавьте обратно, пока не увидите утечку.
Тогда почему бы вам не попробовать программно прочитать узел плитки для каждого уровня?
SKTileMapNode и окружающие его функции невероятно содержат ошибки. Я не удивлен, что у тебя проблемы с этим. У меня есть непосредственный опыт, и я могу сказать вам, что я бы рекомендовал держаться подальше от этого раздела SpriteKit. Вам будет намного проще написать весь свой собственный код для работы вместо SKTileMapNodes (и окружающих функций).
@El Tomato Да, я переместил все узлы плитки в выделенный файл сцены и попытался загрузить этот файл программно, а затем переместить узлы в основную сцену. Но, к сожалению, все равно происходит утечка памяти именно тогда, когда я загружаю сцену с тайловыми узлами.





Попробуй это:
открыть Info.plist файл, добавить новую строку,
ключ: "Предпочитает OpenGL" тип: "булев" значение: "ДА"
SpriteKit теперь по умолчанию работает в режиме Metal, переключение обратно в режим совместимости с OpenGL может быть полезно для некоторых целей отладки, но это не решение в готовом продукте.
Я нашел причину этой проблемы. Все мои тайлсеты находятся в разных файлах, у каждого тайлсета есть свой файл sks. Когда я переместил все наборы тайлов в один файл sks, проблема исчезла. Я предполагаю, что в какой-то момент игра попытается загрузить все существующие наборы тайлов для каждого файла sks и займет слишком много памяти.
вы можете отладить график памяти и отследить эти фиолетовые '!'. Он подскажет откуда течь.