#!/bin/bash # This line is for starting from mac os icon double click cd "$( dirname "$0" )" ## V1.5-corrected: 64 bit version, and ** LOTS OF MEMORY ALLOCATION ** # This is to give information for data collection. # Determine how much your system uses, and then adjust numbers down to avoid waste # # Specifically: By making the memory pools large, we see how much is used. # Then, we can determine what to cut them down to. # # This will probably be the last CMS version; G1GC next. java=/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Commands/java ## V1.4: Java is now customizable (see the above line), thank you oracle for a ## java (1.7) that does not support 32 bit servers for reduced memory consumption. ## V1.3: The -XX:SoftRefLRUPolicyMSPerMB=0 flag got lost! Back in now. ## This flag defaults to 1000, and can cause memory leaks. ## V1.2: We now play with -XX:TargetSurvivorRatio=n to reduce waste in new, permitting more ## space to be used # Configurables: # -d32 is for heap size up to 2.5gb. (NB: apparently only 1.5 gb on microsoft windows?) # Change to "-d64 XX:+UseCompressedOops" if you use more. # ** Mention that flag specifically, do not rely on it being autoset. # ** Known and documented JVM bug -- https://forums.oracle.com/forums/thread.jspa?messageID=10017916 #JVM_SIZE="-d32 -server" JVM_SIZE="-d64 -XX:+UseCompressedOops -server" # CMSInitiatingOccupancyFraction: Determine how frequently to do a full CMS # Special: New "Most important". This primarily affects long-term growth # of the heap. The percentage of used space before CMS starts a collection. # 95 is sufficient for general stuff. 85 is useful for things that suddenly # need a lot. # Dynamic maps, in particular, no longer needs 125 MB of survivor -- it can # get by with 60-75. It can go much lower, but then the garbage collections # need to be started sooner, or else it will never have enough memory and # always grow the heap. # # To clarify: This is obsolete -- completely -- in G1GC. # This needs to be low enough that sudden spurts of temporary memory trigger # garbage collection first. # This should be re-worked as a "MB safety level" -- for example, if you have # 300 MB of tenured, and want at least 30 MB free. But Java don't work that way. # As tenured increases, this will also increase the "keep free" level. CMSInitiatingOccupancyFraction=80 # Memory tuning: # Command line controls total heap, and "new". "Tenured" is the difference. # Bigger "new": Less frequent collections. # These numbers are in "Megabytes", the java "m" suffix. # The rule of memory tuning: # SurvivorSpace * (SurvivorRatio + 2) = New # ("SurvivorSpace" is twice the actual surviving threshold.) # SurvivorSpace * SurvivorRatio = Eden. # Two additional survivor spaces are used to copy surviving objects across minor collections. # MAX: Maximum heap space used. # Does not include permanent (byte/compiled code) # Does not include JVM overhead MAX=3000 # Tenured: Desired long-term storage space # Will vary based on mods, and "loaded chunks" # -- how many parties of players close to each other. # # Starting assumption: 250 for 1 person, plus 50 per group # of players near each other. # # That is a guess. Please report what numbers work for your server. Tenured=450 # Most important tuning number. Survivor. # Making this higher: Fewer full collections, but more wasted space. # During startup, expect this to overflow frequently. # Dynamic maps wants this at least 100, preferrably 125. # Actual space allocated is 2 spaces, each one twice this size. # "waste/overhead" will be two about to three times this number. # *** Maximum of 1/6rd of "new" # Pay attention to the tenuring distribution logs. # *** This should be enough for generation 3 95%+ of the time. *** # ** TOO SMALL WILL KILL YOUR GARBAGE COLLECTION ** # ** TOO BIG WILL WASTE SPACE ** ## SurvivorCopySize=26 ## 26 is too small -- memory consumption keeps going up with dynamic maps # # To clarify: You can easily use 12 here if you do not use dynamic maps. # You can even use less, but the memory savings are not significant. # You can use less if you use lowres maps. # The big memory consumer is low-angle maps; the 30 degree maps of high res, # or the 20 degree maps I use on my server are the big memory consumers. SurvivorCopySize=100 # Survivor target ratio. Java defaults to 50%, which wastes a lot of space. If you know how much # you need (see below), you can set this value higher; this gives less waste and "better performance". TargetSurvivorRatio=90 ## Notes on "SurvivorCopySize": # Flying around in creative mode, in already generated chunks will want # at least 30-35, preferrably 40 meg. # Standing around, single player, can be happy with less than 1. # Even in Mystcraft, with massive amounts of decay everywhere, 95% of the time 1 meg suffices. # Moving around a little, doing basic building/digging, about 3. # # The rule: You want to see "new threshold 4 (max 4)" most of the time. # The total value at age three -- # - age 3: 36712 bytes, 5897520 total # should be less than this 95% of the time. # 12 meg is more than enough for one person with EBXL, Mystcraft, Twilight Forest, # and Custom Ore Gen. Even in EBXL's extreme jungle with Mystcraft's decay littering the ground. # # The single biggest factor is chunks loaded; that will depend more on parties than on players, # and the speed at which they move. Adjust to your server, and your mods. # # Single player won't need that much. Really. # Second most important tuning. Eden. # Making this bigger means less frequent small collections. # General rule: Make this as big as your memory can handle. # Must be at least 2x SurvivorCopySize. Java requires it to be # an integer multiple of that value. desiredEden=250 # Summary: Approximately desiredEden, plus 2 times Survivor, # plus 100, will be used by java to start the heap. Up to a max of MAX. # Script will attempt to ensure at least Tenured space exist; # should exit with a message if it cannot. # # In theory, Java will allocate extra space to new or tenured as needed. # In practice, I've never seen it increase "new". # # See the bottom of the config section for more. # If your shell cannot do math, replace these with an appropriate constant MaxNew=$(($MAX - $Tenured)) ## Survivor=$((2 * $SurvivorCopySize)) ## Working with survivor target. "2" is for 50%. For 90%, it's much closer to 1. ## What we want is 100 / target percentage, as the ratio instead of 2. ## For integer only shell math, we re-write as (100 * survivor) / target, which gives us ## close integer to the desired result -- as close as we can get in the shell. Survivor=$(( ($SurvivorCopySize * 100 ) / $TargetSurvivorRatio )) ## Equally, the "3" in sanity test is from 3 bins -- two survivors, one eden. ## But that does NOT change here -- it's still the sanity test lower limit. sanityTest=$((3 * $Survivor)) if [ $sanityTest -gt $MaxNew ] then echo Memory config error >& 2 exit 1 fi # We cannot use more than MaxNew. # The idea: # 1. Find the multiple of Survivor that is bigger than S and less than MN. # 2. Determine survivor ratio from that. Subtract 2 (java.) # 3. Specify -Xmn for new, and survivor ratio, to set eden and new. # "New" will be Eden plus 2* Survivor. # MaxRatio -- what the ratio is if we use all of maxnew. MaxRatio=$(( ($MaxNew / $Survivor) - 2 )) # DesiredRatio -- what the ratio is based on declared eden space # There is no "-2" here -- this will allocate eden plus 2* survivor. desiredRatio=$(( ($desiredEden / $Survivor) )) # SurvivorSpace * (SurvivorRatio + 2) = New # Now check for "desired Eden". If survivor is not an exact multiple of DE, # then we have just rounded down. Test for this, and if so, see if we can # raise it up (watch out for maxnew) ## TODO! FIXME! This is a cheap approximation if ( [ $(( $desiredRatio + 1 )) -le $MaxRatio ] ) then desiredRatio=$(( $desiredRatio + 1 )) fi desiredNew=$(($Survivor * ($desiredRatio + 2) )) biggerNew=$(($Survivor * ($MaxRatio + 2) )) echo Debug: Max ratio $MaxRatio, desiredRatio $desiredRatio echo Debug: biggerNew $biggerNew, should be less than MaxNew $MaxNew echo Debug: desired eden $desiredEden, survivor $Survivor, actual new $desiredNew # desiredNew: Gives an eden up to, not bigger, than desiredEden. # biggerNew: Gives an eden at least as big as desiredEden. # FIXME: DesiredNew / ratio should be smallest at least as big as desiredEden # This means, if less, then add 1 to ratio and add to new. # # "Bigger" assigns ALL non-tenured memory to new. # Q: Desired numbers? Bigger/Max numbers? # Choose one of these pairs # New space is small -- specified eden. NEW=$desiredNew RATIO=$desiredRatio # Tenured is small -- specified tenured space. ## Should Not Be Needed -- "NewSize" and "MaxNewSize" specified separately. # In theory, Java should now adjust new as neeed. #NEW=$biggerNew #RATIO=$MaxRatio START=$(($NEW + 130)) ## TESTME: Does "MaxNewSize" matter if we have adaptive GC boundary? Does it hurt? # A few more notes ... # -XX:+UseAdaptiveGCBoundary -- apparently, adjust the boundary between new and tenured as needed. # Nice to see; did not know about it before. # Sadly, it seems to have no effect. # -XX:+CMSIncrementalMode: Tells the garbage collector to break the job into many small parts. # May result in better performance. Essential on systems with few cores. exec $java \ -d32 -server \ -Xms${START}m -Xmx${MAX}m \ -XX:NewSize=${NEW}m -XX:MaxNewSize=${MaxNew}m \ -XX:+UseAdaptiveGCBoundary \ -XX:SurvivorRatio=$RATIO \ -XX:TargetSurvivorRatio=$TargetSurvivorRatio \ -XX:CompileThreshold=3000 \ -XX:CMSInitiatingOccupancyFraction=$CMSInitiatingOccupancyFraction \ \ -XX:SoftRefLRUPolicyMSPerMB=0 \ -XX:MaxPermSize=150m \ -XX:+UseConcMarkSweepGC -XX:+UseParNewGC \ -XX:MaxHeapFreeRatio=20 \ -XX:MinHeapFreeRatio=15 \ -XX:MaxTenuringThreshold=4 \ -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution \ -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -Xloggc:GC.log \ -jar new_server.jar nogui 147MystTest # The last word of that exec statement -- '147test' -- is just something that shows up in # the process list, so I can tell which process is which server (each copy of this script # has a different name in that field).