ID:2180508
 
(See the best response by Lummox JR.)
Crazy high memory usage. Tips for optimization?
What do these numbers mean?

https://gyazo.com/39299185f48f62a3c0d16d48c121e75e
It means your map is entirely too large and entirely too filled with things, especially things that generating images and lists.
In response to Nadrew
This doesn't really answer my question.
It does though Mav. Nadrew is saying that you just got wayyyy too much going on in one map.

I love big maps, but I've been shying away from them for smaller instanced maps. You also might be having issues with mob, obj, turf, atom's having too many variables. Excess common variables result in poor performance. Another thing Lummox mentioned the other day that I didn't even think myself of is that large black spaces also will mess with optimization. So if you have multiple z levels of blackness, if possible, condensing your map to one z level and just teleporting players throughout rather than through z levels is more optimal.

Also try pinpointing variables where they're needed, like player specific variables shouldn't be in /mob, they should be more specific like /mob/player or better yet /mob/player/player1. Player1 being a character whom has unique variables.

The less variables, lists, etc. that atoms have the better. Try to once again, focus only necessary variables and lists where they are needed and to downsize on your total map size whether that be empty z levels or instancing off some areas into other maps.

If you have just like a big list of variables lying around or could give us insight into some of your lists you're generating. That also could help us provide you with more insight on optimization.
In response to Flame Guardian
https://gyazo.com/71c2b419d8ec0aeaaa5ed40f3b398328
5 300x300 village maps, 1000x1000 interior and 1000x1000 world map all add up to around 1050 mb in daemon.
So I created a new map with just a plain grass turf 50x50. Daemons down to around 27mb.
DS is around 70mb and jumps up to 100mb after I log into the game.
As for variables, how much memory can a couple variables take up though really?
mob/var/list/skills = list()
mob
var
list/affinity=list()
based_mode="null"
future_one = 0
future_two = 0
future_three = 0
tmp/skinowner = 0
tmp/list/cutters = list()
MissionTargetCount
sand_walk = 0
blood_craze = 0
blood_effect = 0
inorganic = 0
tell = 0
age = 0
pop1 = 0
pop2 = 0
pop3 = 0
pop4 = 0
pop5 = 0
pop6 = 0
pop7 = 0
pop8 = 0
pop9 = 0
pop10 = 0
sennin_staff = 0
susanoo_overlays = 0
tmp/replacement_active = 0
tmp/turf/replacement_loc = 0
missing_mouse = 0
cursed = 0
critical_mode = 0
rate_level = 0
canwalk=1
Tank=0
rage = 0
swagged_out = 0
list/bloodrem=list()
tmp/obj/war_object/warring
tmp/area
skillusecool=0
tmp/hassword=0
pressured=0
alreadydied=0
died_warning=0
nopktime=0
scalpol=0
scalpoltime=0
sakpunch2=0
rename_count = 0
sakpunch=0
bonedrill=0
bonedrilluses=0
qued2=0
tmp/alertcool=0
cantreact=0
MissionCool=0
list/player_gui=list()
Hastargetpos=0
kstun=0
surname=""
firstname=""
ask = 0
adren=0
astrbuff=0
MorningP=0
arfxbuff=0
aconbuff=0
win=0
lose=0
VillageKills=0
movepenalty=0
lastwitnessing=0
list/pins=list()
projectileblocking=0
maxsupplies=100
Poison=0
Recovery=0
mob/human/Puppet/Puppet1=0
mob/human/Puppet/Puppet2=0
phenged=0
Primary=0
votecool=0
votecool2=0
FU=0
movedrecently=0
medicing=0
hasjoinverb=0
hasleaveverb=0
incombo=0
AFK=0
AFK2=0
overband=0
Aki=0
qued=0
demonmirrored=0
list/Imgs=list()
usemove=0
tajuu=0
larch=0
//mission
mob/var/mob/human/player/npc/leading=null
disp
MissionClass
mob/MissionTarget
mob/MissionTarget_Two
TargetLocation
MissionTime
MissionTimeLeft
MissionType
MissionLocation
Missionstatus=0
danzo=0
Rank_A=0
Rank_S=0
Rank_B=0
Rank_C=0
Rank_D=0
pay=0
//end mission
realname
henged=0
haschuuninwatch=0
cexam=0
frozen=0
inchuunin=0
sleeping=0
curpick=0
sandarmor=0
gsandarmor=0
factionpoints=0
hasbonesword=0
initialized=0
targetpractice=0
protected=0
screener=list()
mob/lasthostile
bounty=0
boneharden=0
dojo=0
oldx
oldy
oldz
inarena=0
spectate=0
has_tourney_verbs=0
//oocverbs
mute=0
tempmute=0
talkcool=0
talktimes=0
talkcooling=0
say=1
owner

//olays
weapon[]
undershirt
overshirt
armor
pants
legarmor
armarmor
facearmor
glasses
cloak
back
shoes
special
face
hair_type=0
hair_color="#000000"
//non olay
runlevel=0
kaiten=0
gatestress=0
gatetime=0
gatepwn=0
gate=0
resurrection=0
mole=0
sharingan=0
bandaged=0
canattack=1
busy=0
soldierpill=0
targetable=1
mane=0
maned=0
rasengan=0
chakrablocked=0
gentlefist=0
asleep=0
shopping=0
eye_r=0
eye_g=0
eye_b=0
pk=0
nudge=0
skill
macro1
macro2
macro3
macro4
macro5
macro6
macro7
macro8
macro9
macro10
macro11
macro12
macro13
////////////
macro14
macro15
macro16
macro17
macro18
macro19
macro20
macro21
macro22
macro23
macro24
macro25
macro26

tmp/hidestat=0
skillpoints=0
levelpoints=0
tmp/pstr=0
tmp/pcon=0
tmp/pint=0
tmp/prfx=0
tmp/controlmob=0
tmp/paralysed=0
tmp/waterlogged=0
// tmp/targetaddress=0
mob/target=0
tmp/canmove=1
money=0
stamina = 1000
curstamina=1000
chakra =300
curchakra=300
str=50
tmp/strbuff=0
supplies=100
tmp/strneg=0
con=50
tmp/byakugan=0
tmp/conbuff=0
tmp/makeswamp=0
tmp/conneg=0
rfx=50
combomax=2
tmp/rfxbuff=0
tmp/rfxneg=0
tmp/shun=0
specialover=""
levitate=0
int=50
tmp/intbuff=0
tmp/interact=0
intneg=0
maxwound=100
curwound=0
exp=0
elevel=1
body=0
blevel=1
injury[20]
staminaregen=17 //%
chakraregen=50 //pts
//skills[0]
skillspassive[50]
tmp/stunned=0
tmp/attackbreak=0
//backup
backupoverlays[]
backupicon=0
backuptargetaddress=0
ko=0
//village="Missing"
tmp/blocked=0
tmp/kocheck=0
tmp/usedelay=0
ironskin=0
icon_name="base_m1"
playergender="male"
tmp/swamplogged=0
boneuses=0
clan
elements[0]
tmp/gen_effective_int = 0
tmp/gen_cancel_cooldown = 0
tmp/move_stun = 0
tmp/handseal_stun = 0
tmp/gentle_fist_block = 0
proc
LocationEnter(dropoff)

human/player
npc


mob/var/list/pet = list()
mob/var/a1 = 0

mob/human/var
//owner = 0
bunshinowner = ""
ownerkey = ""

obj
var
owner
The thing is, those variables exist for everything of those types, and according to your memory output you have quite a lot of objects and mobs on the map, so it will compound as that number increases.

You should cut things from NPCs that only players need and vise versa, as well as avoiding things like initializing lists until they're needed.
Variables only take up memory if it's changed from the compile value or it's a reference like list() or new().

The massive majority of the memory is in images and icons.

~1.5GB (guestimated by byond, most likely lower) is from images.

objects and mobs are only taking a few megabytes.

I'm seeing ~700MB from lists, mostly contents lists i'd guess, but it could be something else.

I would avoid leaving empty lists around, instead create the list when you actually add something to it (just check before hand) and whenever you remove something from the list, check if it's empty after and if so, set the var back to null.

Next would be to look at that images memory, some of it is just going to be from the 7 MILLION turfs your world has.

I would either merge some of those smaller z-levels to fit in a single 1000 z level, or split up the 1000x1000 levels. When a zlevel is "smaller" then the biggest zlevel, byond auto sizes it to be the same size as the biggest zlevel. So those 300x300 village maps are all actually 1000x1000.

That being said are you creating icon or image objects in your game code? if so, you might leaving some of those around and they are taking up memory, could look into that.

In response to MrStonedOne
Thanks for all of the info. I noticed that after about 10 minutes of hosting daemon drops to around 50mb but fluctuates back to around 500-600mb. I'll probably just try unreal or something. Does using map pages change anything? I'm using 7 different maps instead of one with several z locations.
Those image and list counts are freaking insane--especially images. That's the most obvious place to look. Why so many of each?

Like Nadrew said, one of the things you're doing is initializing lists you don't need right away. That's a bad idea for both performance and memory.
In response to Lummox JR
I have no idea where all those images and lists are even coming from.
Both are probably easy to find. If you look at your mob definition, a lot of those lists for instance are obvious: You have quite a lot of list vars, and you're initializing every one of them.

I'm certain the images wouldn't be hard to track down either.

If you send me your source I'm happy to take a quick look and identify the hot spots.
That's pretty generous of you to take the time to do that Lummox!

In case you're out of the loop Mav472, Lummox is the safest person on BYOND to send your source to.
In response to Flame Guardian
Best response
Flame Guardian wrote:
In case you're out of the loop Mav472, Lummox is the safest person on BYOND to send your source to.

Also money.
In response to Lummox JR
Lummox JR wrote:
Flame Guardian wrote:
In case you're out of the loop Mav472, Lummox is the safest person on BYOND to send your source to.

Also money.

Can confirm. I have sent several hundred dollars to BYOND over the years, and NOBODY else here has seen it since.
In response to Lummox JR
source too big.

I removed a whole bunch of crap and daemon is down to 80mb.
https://gyazo.com/3bb3b7627081553a4e84a84eab2d6935

I still don't really know how to interpret this but some of these numbers are obviously matching up for a reason. I guess my turfs have lists under them or something.

Any ideas of where I would find the source of these images?
In response to Mav472
Mav472 wrote:
source too big.

I removed a whole bunch of crap and daemon is down to 80mb.
https://gyazo.com/3bb3b7627081553a4e84a84eab2d6935

I still don't really know how to interpret this but some of these numbers are obviously matching up for a reason. I guess my turfs have lists under them or something.

Any ideas of where I would find the source of these images?


BYOND's main developer just volunteered to look through your source. It being too big isn't really a valid excuse.

filedropper.com can hold gigs, make a source zip file through Dream Maker(build > package files > world source file... Something like that), upload it, send the link privately to Lummox, ???, profit,
In response to Mav472
Mav472 wrote:
source too big.

I removed a whole bunch of crap and daemon is down to 80mb.

I don't actually intend to compile your source, so I don't need any of the images, sounds, etc. All I really need is the .dme and .dm files and to know what libraries you're including (if they're relevant).

My purpose here would be to simply look through your source and give you a good first-pass idea as to where to look, and how I found it. The reason I volunteered to look is because I'm convinced that this many lists and images won't be nearly as hard to find as you think. I don't expect it will take me very long.

What I won't be doing is drilling down in much depth beyond that first pass. But finding lists and images really ought to be easy enough. Just looking at your mob definition, it's clear that lists are going to be a problem from those alone, which makes me think there may be something similar going on for objs and/or turfs. The images are the bigger deal, but I think I can find those without much trouble.
In response to Lummox JR
Sent. I just didn't want to throw a whole bunch of crap on your lap all at once. No libraries are included.
Okay, brace yourself because this is a great big list of things I found while searching for the list and image problems. It is not exhaustive. It took longer than I thought to go through, but mostly I kept with it out of fascination. Suffice it to say this code needs a lot of work.



The mob definition in Variables.dm is still wrong. You're initializing about a dozen list vars when you should only be initializing them as needed. In order in that file:

skills
affinity
cutters
bloodrem
player_gui
pins
Imgs
screener
weapon
injury
skillspassive
backupoverlays
elements
pet

Side note, not related to the problem at hand: What's with all those skill/macroXX vars? Clearly that's a place you should be using a list.

Also unrelated, but I saw this in searching: That Bird_Blast() proc is an absolute train wreck. All those dir==xx || dir==yy checks--very very bad.

I noticed you have mob vars defined in some other places too, like in Damage.dm. You have a crapload of vars already in Variables.dm, but they should really all be kept in one place.

Damage.dm is full of usr abuse. I assume that's endemic throughout the code, so I won't mention it again, but I'm putting this in bold because it's hugely important: No put usr in proc. Ungh.

More mob vars in Masd.dm. Do a regex search on ^mob/var for all included files and if that line is not in Variables.dm, move it there. Having the vars spread out all over the place is hurting you.

Speaking of rogue mob vars, found another initialized list var in Missions.dm: mission_people

And another rogue mob var with an initialized list in NewRegeneration(Masd).dm: medals

You have initialized list vars in /client in Passives.dm: passive_imgs and _passive_cache. They probably aren't as bad and there's not as much point changing them, since you won't have a zillion clients at once and a hidden init proc for a client isn't so terrible.

In that same file, obj/gui/passives has two initialized lists: digit1 and digit2. Also those lists are being filled by 10 and 6 images, respectively, which helps account for part of the image problem; every single /obj/gui/passives object has 16 images in it. Do you have a lot of these objects? If so, that's a big, big problem. Why do you need all those images? This part of the code doesn't make any sense.

In Projectile Mechanics.dm: obj/projectile/var/list/Grabbed=list(). Every projectile has an initialized list, and that list is created in a hidden init proc. Very bad. Like in the above cases, don't initialize the list until you need it.

I'm still finding lots and lots and lots of mob vars sprinkled a few at a time in just about every file. Don't put off that regex search.

RP.dm: mob/var/list/carrying=new. Another initialized list for all mobs.

In S_Rank.dm, I found some attached to an NPC, but I'll skip those; they may be important and are filled in with values anyway. But in that same file, you have another rogue mob var, npc_mission_targets, which again is an initialized list. I haven't been keeping count but we're around two dozen at this point--per mob.

In Save_Handling_new.dm you have another client var that initializes a list; as above, I think you can probably not worry about this, but you should still consolidate all of your client vars into one file.

Aburame.dm: mob/var/list/trackers = new

Found this as I was still looking for lists: In Deidara.dm, under C2 in the Use() proc, you're creating a crapload of images to add them to underlays, and then doing the same thing to remove them again. No bueno. The very least you could do is simply create one image and change its values. This is probably not contributing to your image problem, unless something's wrong with the deletion (which at this point I'm not ruling out) as in a badly overridden Del(). I'll look for that later. Still, even if this is not contributing to the image problem, this whole section is just terrible form. Find another way.

Found these by accident in Haku.dm: You're doing a similar thing to the image problem I just mentioned in obj/snowfall/New() (if nothing else this cries out for a loop!), and just below that in Ice_Land() you're creating a zillion local vars where a loop and a list would obviously be better form. The image thing appears in a lot of other places too, so I won't mention it further unless I find evidence that it could be contributing to the image buildup problem, but you really need to use loops for those cases too. If nothing else you can seriously clean up your code's readability and maintainability by addressing things like these.

In Jashin.dm, two more rogue mob vars that are initialized lists: Contract2 and circles.

In Kakashi(Masd).dm, another one: kamuis.

Nearly missed this one in Namikaze(Masd).dm, but only because I was still searching for var/list and hadn't searched for [] or [0] yet: hiraishin. In that same file, you have a much, much bigger problem in a list var you've given to every single obj in the world: barrier_things. I bet barrier_things is a huge contributor to your list problem.

Obito(Masd).dm: barriers.

In skills\S_Rank.dm (I don't like at all that these files have the same name, even in different directories), you have a very bad list var commented out, thank goodness: atom/movable/var/list/Grabbed2=list(). Even though that's commented out, you should kill it with fire.

The lightning round!
Sage.dm: mob/var/list/bunshins.
Scavenger(Masd).dm: active_masks.
Scorch(Masd).dm: locations.
Sensory.dm: sense.
Shin(Masd).dm: shins.
Shisui(Masd).dm: flickers.
Six_Paths(Masd).dm: six_pains, brothers.
Water.dm: water_list.
Weapon.dm: tagging, in_tag.
Zetsu.dm: flowers, copied_skills.
YGO.dm: dueling_chat, DECKS, current_deck, current_hand, current_grave, current_rfp, editing_deck.

Now searching for regex \[\d*\], I'm finding more list cases.

Names.dm: name_img.

Not sure if this is a problem, but obj/mapinfo has three such lists: village_players, alert_cool, and alert_imgs. Hopefully there aren't a lot of these.

NewRegen.dm: old_lays.
options.dm: macro_set.

Ran into this by accident in Player Interactions.dm, but there are four image vars for all atom/movables. They're not being initialized, but if you end up creating a lot of images and not getting rid of them, that might be contributing to the image issue.

StatBars.dm: hud_img.
target.dm: active_targets, targets, target_img, active_target_img, targeted_by.
Trigger Mechanics.dm: triggers.

Going back to Kakashi(Masd).dm: Lightning_Kunais.

The image problem is honestly probably going to be too hard to pin down easily with the way the var definitions are scattered, and the bad way images are being used to create/remove overlays all over (without even using loops). Massive cleanup is going to be needed to track that down.

I've been looking at Del(), and you're calling sleep() in a number of Del() procs. Why? Del() should be called only if you've done a manual delete or if the object is recycled, so sleep() is never ever appropriate there.

I noticed in FX.dm you've got the same Del() proc repeating a million times. Why not define that one level up so you don't have to do that? That will also prevent any unexpected copy-paste errors from one Del() maybe being different from the others.

world/Del() appears to be split up into several procs. Very bad juju. Don't do that. Have just one del proc for the world.

SpeechBubble/Del() does not call ..() and therefore is never properly deleted. Guess what: It has a _text list that contains images. That's likely a BIG contributor to your image problem.

obj/Itachi_Amaterasu/Head/New() calls Del() directly instead of using del. The same object's Del() proc does not call ..(); it only sets src.loc to null, which is redundant.

obj/AMATERASU_OP/Head has the exact same problems.

Lasercircus in Storm.dm has a broken Del() that doesn't call ..().

ninja_tournament.End() calls Del() directly instead of del.

So does capture_the_flag.End().

Push_Wave5 in explosion.dm isn't broken per se, but the Del() that sets src.loc to null and then calls ..() is entirely pointless. Just lose that Del() proc completely. Same with Push_Wave_old.



And that's where I left off. These are my overall notes:

1) I can't stress this enough: For generic mobs, clients, generic objs, generic atoms, and whatever else, put all of their vars in the same file. You have Variables.dm for mobs, but then you have mob vars scattered in literally almost every other file. This is making it darn near impossible for you to track down big-picture problems.

2) As was noted earlier in this thread, don't initialize any list vars until you need them. Define all list vars like so: var/list/varname. No new, no list(), and no brackets. I did not keep count of the mob vars that have this problem, but you have upwards of three dozen initialized lists--if not more--for every single mob in the game. That adds up fast. You have at least one for every obj, and that adds up faster because you probably have many, many more objs.

3) Make sure you always call ..() in Del(). Never call Del() directly; always call it as del(). Never sleep in Del(). Setting src.loc=null in Del() is redundant; if that's all the proc does, get rid of the proc.

4) The images problem remains something of a mystery, but that broken Del() in SpeechBubble is quite possibly the #1 factor. I just had a hunch something wasn't being deleted properly, which is why I went on a Del() search to begin with.

5) A pattern I'm seeing very, very frequently in your code is big blocks of like 49 images being added to, or removed from, overlays. In every case you would be better off A) using a loop, B) using just one image and changing its vars in that loop, C) adding all the images's appearances to a list before adding to overlays, D) adding/removing the list to overlays in one shot after the loop. In most of these cases you'd also be way better off letting a single universal proc handle this, so you can clean up your code.

6) Another pattern I'm seeing a lot of is vars like var0, var1, var2, var3, and so on--often very many of them, like that mob/var/skill/macroXX set, or that case in Ice_Land(). Those things should be changed.

7) Move all your world/Del() procs into one place, one single world/Del() proc.

8) No put usr in proc. Ungh.