Software Development, Web Design, Training

Oct-25-2015

CFCamp Notes - The tale of performance and memory - Gert Franz & Michael Offner-Streit

(I took screenshots of some of the slides, but don't have a great way to get them off my phone at the moment. I'll add them into the notes as soon as I can.)

How do you solve your performance issues?
one by one.
try to analyze from a performance and bad coding perspective
have to define whether performance is/isn't important
if a task runes once a month at 3am when the server isn't busy, it doesn't matter
if "basic response time" is 2+ seconds, it might be worth looking at

measure your baseline --
find out how fast is your site
what is your baseline --
use some load testing tools in order to check the perf of your web app
jmeter
loadrunner
Web Stress Tool

then, define your goals
what do i want to achieve? < 250ms response time, for example
i want all pages to load < 2 seconds
indexing max 20 seconds
longest schedule task max 1 minute
make sure the goals are achievable

identify the problems
find out what your issue is and why the goal you have set is not achievable
missing resources (memory, under-performant code, etc)
could also be hardware, bad network, wrong config, etc.

Resources are a very limited thing
every resource you are using is limited in some way
always have to be aware of this
always think "can this scale? what will happen when this code has 10,000 users/sec?"

file system --
mostly straight forward
local drives over network drives (stick to local file system when you can)
memory over local file system
limit application.cfc search to a minimum
-- don't make the engine hunt in various places for Applicaiton.cfc/CFM -- loses performance (up to 20% change)

inspect template setting in the Lucee admin

threads --
a highly limited resource
really be careful
don't open threads for every user if you can avoid it
use cfthread type=task if no join is necessary
-- doesn't open a new thread, only creates a task

always be aware of running cfthread

memory --
easily over used, especially when it comes to scope
use the correct scopes
keeps the memory usage as low as possible
use the right JVM tuning techniques
think about scaling the system
the session can blow up when you have a lot of users. lots of users = lots of sessions
session scope is unpredictable -- you never know how big this is going to get, depends on how many users are on your site.
JVM memory is as precious as unicorn blood
-- really important

memory leaks --
often apps have issues with memory.
= base memory increases over time.

what is a memory leak?
erroneous programming, "forgot" to release memory
-application freeze
-operating system froze
-etc

With Java, the garbage collector was introduced
no need to allocate/release memory. "pointers" are done automatically now.
all unreferenced variables will be "garbage collected"

erroneous program designs result in forgotten pointers
these variables will never be garbage collected and will linger in memory
the garbage collector cannot remove these since they are still referred to
example: application.mySession[iuserid] = session
user's session cannot be deleted because application.mySession[userid] still references "session" so the session can never be deleted

so how do you find a memory leak?
hard way -- look at the code with your eyes and try to figure it out "by hand", trial and error
better ways --
analyze a heap dump of the JVM

[Collecting a heap dump]

this is a "stop the world" action
-- nothing else happens on your server for 2, 3, 10 seconds (depending on the size of the JVM)
(same can be done on ACF)

java dump file can be HUGE. if you make one, zip it.
load it into a tool like "map" (comes with CF Eclipse, installed by default)

learning by doing
most people, problems arise because they don't SEE the memory. they just ASSUME what the problem is
most people have no clue where the memory is being USED.

(tend to limit caches to SIZES not to a number of objects)

[PIC]
watch it with closures. can have memory leaks because of how they include a reference to the parent variables scope

cfproperty accessors
most of the memory of a bean is consumed by the getters/setters
common problem with beans.
change to store data in a struct instead when possible -- much less RAM used. no accessors.

reduce session timeout
are they REALLY necessary for 20 minutes before timing out?
that means = for 20 minutes if the user isn't doing ANYthing
instead, use Session Storage (Railo, Lucee) -- can store the session in a cache or data source. so instead of using memory, the session is stored in a database on a different server, for example
this.sessionStorage = "name of the cache"

lucee 5 has a big overhaul of the language
improved the size of components, for ex
lucee 5 is 242MB instead of the 387MB it was before

lucee stores CFCs as 1 class file (as opposed to ACF)

ArrayAppend is much faster than the .append member function in ACF
-- have to check the type of the object. is it an array, an object, whatever, so it knows what kind of "append" to do. this causes a slow-down

StructKeyExists() vs .keyExists() member function
.keyExists is 4 to 26 times slower!
compiler can't detect if it's an array/hash or not. only happens at RUN time, hence the overhead.

querySetCell() vs .setCell()
same issue

ternary Operator ? : instead of if/else

file include with the upper case / lower case not matching
not a HUGE difference but maybe 10% gain depending on the system

elvis operator ?:

looping in array
for(i = 1; i < 500; i++ )
a += arr[ i ];

vs
arr.each( function(elem) { … } );
in ACF this can get REALLY slow
looping thru closures, might have an issue with passing references in/out

cfsilent
STILL produces output code even when you tell CF not to.
[SLIDE]
even when you use output=false, it has some memory issues
this is improved in CF12 but don't have lots of details
CFscript is "immune" to this issue, as it doesn't produce output by default (unless you're calling WriteOutput, WriteDump, etc)