mboost-dp1

Terracotta

Cache løser garbage collection-problem

- Via DZone -

Firmaet Terracotta hævder at have løst problemet med dårlig performance på grund af garbage collection i Java.

Terracotta har netop sendt sin BigMemory-teknologi i betatest. Det er en udvidelse til firmaets cacheprodukt, Enterprise Ehcache.

Problemerne med svartider opstår, når Java-programmer anvender store mængder arbejdslager. Så skal Java Virtual Machine indimellem rydde op i lageret og frigive de områder, der ikke længere anvendes. Det kan give uforudsigelige udsving i svartiderne.

Går uden om Javas garbage collection
Ifølge Terracotta løser kombinationen af Enterprise Ehcache og BigMemory problemet ved helt at forbigå Javas indbyggede garbage collection. Data placeres i et cachelager uden for heap’en. Dermed får man forudsigelige svartider.

Firmaet har testet konfigurationer med cachelagre på over 350 GB. Steven Harris fra Terracotta skriver, at den store cache næsten ikke giver negativ indflydelse på ydeevnen.

Med løsningen kan firmaer slipper for fintune garbage collection i Java, skriver Terracotta i en pressemeddelelse.





Gå til bund
Gravatar #1 - squad2nd
21. sep. 2010 10:43
Der står intet på websiden om hvad man kan forvente sig af licens-priser. Det lyder til at blive en dyr historie.

Men skidesmart, hvis det virker. Der findes ikke noget bedre end optimering.
Gravatar #2 - mathiass
21. sep. 2010 10:44
Det er et rimelig skidt summary, det her. Så vidt jeg kan forstå går teknologien ud på at gemme sine objekter uden for heapen (i en separat process) for på den måde at undgå garbage collection. Denne løsning betyder at det kun er anvendeligt til caching gennem EHCache på samme måde som at man også kan gemme ting på disken for ikke at have det i memory. Forskellen er så at det fysisk ligger i memory i stedet for på disken fordi det er hurtigere.

Det virker helt ærligt hverken særlig smart, særlig nyt eller særlig opfindsomt. Er der nogen der har en bedre forståelse for hvad den gode idé egentlig er her?

Hvis man ikke vil have pauser i sit Java program under udførsel, så har man også en ganske fin mulighed i den indbyggede concurrent garbage collector. Og så ligger objekterne vel at mærke i heapen. Eller er jeg helt gal på den?
Gravatar #3 - reonekot
21. sep. 2010 12:02
Er enig med #2. Det er en rimelig skidt overskrift, efter som hele teknologien jo netop ikke er GC:
"BigMemory is a pure Java add-on to Enterprise Ehcache that provides an off-heap cache not subject to garbage collection."
Så ud fra deres hjemmeside er det altså et cache produkt, skrevet i Java, men som ikke benytter Java's GC til at allokere hukommelse. (Og har ikke noget med "Hurtig garbage collection til Java" at gøre.)
Gravatar #4 - mgX
21. sep. 2010 13:07
Og forskellen på det de foretager sig, og en objectpool man selv implementerer er....?

Og nu har java's GC aldrig nogen sinde været effektiv... Hvis man sammenligner med CLR GCen, er java's langt underlegen. Det handler om løbende at behandle hukommelsen, compacte heapet løbende, og så lave cleanups kun når det er nødvendigt og der er resources til det. Hvis java GCen itererer over samtlige blocks i hukommelsen under en cleanup, har den seriøst spildt tiden mens hukommelsen bliver allokeret og compactet.

Det nummer de har lavet, er en ny dum iriterende cache der ikke løser nogle problemer overhovedet. Tværtimod tilføjer den betydeligt IPC overhead til lookups. En mulighed for at sænke overheaded, er ved at bruge shared memory, så man slipper for at sende objekter mellem processer. Ved ikke helt om java understøtter det out of the box, men man kan vel implementere det selv forholdsvis nemt.
Gravatar #5 - Torben B. Sørensen
21. sep. 2010 13:09
#2 og #3: I har ret. Jeg har nu ændret i artiklen, så den forhåbentlig er mere dækkende. Tak for input!

Der er i øvrigt mere diskussion af emnet og alternative løsningsmuligheder her.
Gravatar #6 - arne_v
25. sep. 2010 02:29
mgX (4) skrev:
Og nu har java's GC aldrig nogen sinde været effektiv... Hvis man sammenligner med CLR GCen, er java's langt underlegen. Det handler om løbende at behandle hukommelsen, compacte heapet løbende, og så lave cleanups kun når det er nødvendigt og der er resources til det. Hvis java GCen itererer over samtlige blocks i hukommelsen under en cleanup, har den seriøst spildt tiden mens hukommelsen bliver allokeret og compactet.


Der er en meget nem måde at genkende de fleste uvidende der udtaler sig om at Java er langsomt: de taler altid om "Java" som sådan. Java er en specifikation. SUN (nu ejet af Oracle), IBM, BEA (nu ejet af Oracle), Oracle, HP, Apple etc. laver implementationer af denne specifikation. Implementationer med vidt forskellige performance karakteristika. SUN Java kommer endvidere med to forskellige JVM'er - client og server.

Med hensyn til garbage collection bliver det endnu mere grumset, da bl.a. SUN Java giver mulighed for at vælge mellem forskellige GC algoritmer.

For at illustrere lavede jeg lige en simpel lille test.

Resultatet blev som følger (Mo/s = Million objects/second, både allokering og GC da det er svært at GC'e objekter uden at allokere dem først).

32 bit Windows - 1 core
=======================

Objects size 0-100 bytes
------------------------

IBM JVM 1.6 ---- 7.88 Mo/s
IBM JVM 1.5 ---- 7.80 Mo/s
SUN Server JVM 1.5 (ParallelGC) ---- 3.25 Mo/s
SUN Server JVM 1.6 (ParallelGC) ---- 3.19 Mo/s
SUN Server JVM 1.5 (ConcMarkSweepGC) ---- 3.19 Mo/s
SUN Server JVM 1.5 (SerialGC) ---- 3.18 Mo/s
SUN Server JVM 1.5 (default GC) ---- 3.16 Mo/s
SUN Server JVM 1.6 (ConcMarkSweepGC) ---- 3.12 Mo/s
SUN Server JVM 1.6 (default GC) ---- 3.11 Mo/s
SUN Server JVM 1.6 (SerialGC) ---- 3.07 Mo/s
SUN Client JVM 1.6 ---- 2.95 Mo/s
SUN Client JVM 1.5 ---- 2.67 Mo/s
BEA JVM 1.5 ---- 2.58 Mo/s
MS CLR 4.0 ---- 2.41 Mo/s
MS CLR 1.1 ---- 2.34 Mo/s
BEA JVM 1.6 ---- 2.21 Mo/s
MS CLR 2.0 ---- 2.18 Mo/s

Objects size 0-10000 bytes
--------------------------

IBM JVM 1.6 ---- 0.67 Mo/s
IBM JVM 1.5 ---- 0.65 Mo/s
BEA JVM 1.6 ---- 0.61 Mo/s
BEA JVM 1.5 ---- 0.44 Mo/s
SUN Server JVM 1.5 (default GC) ---- 0.24 Mo/s
SUN Client JVM 1.6 ---- 0.23 Mo/s
SUN Server JVM 1.6 (default GC) ---- 0.23 Mo/s
SUN Server JVM 1.6 (ConcMarkSweepGC) ---- 0.23 Mo/s
SUN Server JVM 1.6 (ParallelGC) ---- 0.23 Mo/s
SUN Server JVM 1.6 (SerialGC) ---- 0.23 Mo/s
SUN Client JVM 1.5 ---- 0.23 Mo/s
SUN Server JVM 1.5 (ConcMarkSweepGC) ---- 0.23 Mo/s
SUN Server JVM 1.5 (ParallelGC) ---- 0.22 Mo/s
SUN Server JVM 1.5 (SerialGC) ---- 0.22 Mo/s
MS CLR 4.0 ---- 0.14 Mo/s
MS CLR 1.1 ---- 0.13 Mo/s
MS CLR 2.0 ---- 0.12 Mo/s

32 bit Windows - 2 cores
========================

Objects size 0-100 bytes
------------------------

IBM JVM 1.6 ---- 14.94 Mo/s
SUN Server JVM 1.6 (SerialGC) ---- 10.59 Mo/s
SUN Server JVM 1.6 (default GC) ---- 10.56 Mo/s
SUN Server JVM 1.6 (ConcMarkSweepGC) ---- 10.50 Mo/s
SUN Server JVM 1.6 (ParallelGC) ---- 7.24 Mo/s
SUN Client JVM 1.6 ---- 6.88 Mo/s
MS CLR 2.0 ---- 2.85 Mo/s

Objects size 0-10000 bytes
--------------------------

IBM JVM 1.6 ---- 0.98 Mo/s
SUN Server JVM 1.6 (ConcMarkSweepGC) ---- 0.59 Mo/s
SUN Server JVM 1.6 (SerialGC) ---- 0.57 Mo/s
SUN Server JVM 1.6 (default GC) ---- 0.55 Mo/s
SUN Server JVM 1.6 (ParallelGC) ---- 0.47 Mo/s
SUN Client JVM 1.6 ---- 0.45 Mo/s
MS CLR 2.0 ---- 0.20 Mo/s

Vi ser at der er ganske betragtelig forskel på de forskellige JVM'er.

Og påstanden om at Java's GC er langt underlegen bliver ikke ligefrem underbygget - for nu at udtrykke det mildt.
Gravatar #7 - arne_v
25. sep. 2010 02:30

import java.util.Random;

public class GCTest {
private static final int MIN_LVL = 0;
private static final int MAX_LVL = 5;
private static final int MIN_CHLD = 2;
private static final int MAX_CHLD = 10;
private static final int NREPL = 100;
private static int objcount;
private static final Random rng = new Random();
private static int getRanInt(int low, int high) {
return rng.nextInt(high - low + 1) + low;
}
private static class AnyObject {
private Object o;
public AnyObject(int lvl, int siz) {
if(lvl > 0) {
AnyObject[] o2 = new AnyObject[getRanInt(MIN_CHLD, MAX_CHLD)];
for(int i = 0; i < o2.length; i++) {
o2[i] = new AnyObject(lvl - 1, siz);
}
o = o2;
} else {
o = new byte[getRanInt(0, siz)];
}
objcount += 2;
}
public Object getObject() {
return o;
}
}
public static void test(int siz) {
objcount = 0;
int topobj = 1000000000 / (int)Math.pow((MAX_CHLD + MIN_CHLD)/2, MAX_LVL) / siz;
long t1 = System.currentTimeMillis();
AnyObject[] a = new AnyObject[topobj];
for(int i = 0; i < NREPL * a.length; i++) {
a[getRanInt(0, a.length-1)] = new AnyObject(getRanInt(MIN_LVL, MAX_LVL), siz);
}
long t2 = System.currentTimeMillis();
System.out.printf("Objects size 0-%d bytes : %d top objects %.1f million objects in %.1f seconds = %.2f million objects/second\n",
siz, topobj, objcount/1000000.0, (t2-t1)/1000.0, objcount/(t2-t1)/1000.0);
}
public static void main(String[] args) {
System.out.println(System.getProperty("java.vendor") + " " + System.getProperty("java.vm.name") + " " + System.getProperty("java.version"));
test(100);
test(10000);
}
}
Gravatar #8 - arne_v
25. sep. 2010 02:30

using System;

namespace E
{
public class GCTest
{
private const int MIN_LVL = 0;
private const int MAX_LVL = 5;
private const int MIN_CHLD = 2;
private const int MAX_CHLD = 10;
private const int NREPL = 100;
private static int objcount;
private static readonly Random rng = new Random();
private static int GetRanInt(int low, int high)
{
return rng.Next(low, high + 1);
}
private class AnyObject
{
private Object o;
public AnyObject(int lvl, int siz)
{
if(lvl > 0)
{
AnyObject[] o2 = new AnyObject[GetRanInt(MIN_CHLD, MAX_CHLD)];
for(int i = 0; i < o2.Length; i++)
{
o2[i] = new AnyObject(lvl - 1, siz);
}
o = o2;
}
else
{
o = new byte[GetRanInt(0, siz)];
}
objcount += 2;
}
public object Object
{
get { return o; }
}
}
public static void Test(int siz)
{
objcount = 0;
int topobj = 1000000000 / (int)Math.Pow((MAX_CHLD + MIN_CHLD)/2, MAX_LVL) / siz;
DateTime t1 = DateTime.Now;
AnyObject[] a = new AnyObject[topobj];
for(int i = 0; i < NREPL * a.Length; i++)
{
a[GetRanInt(0, a.Length-1)] = new AnyObject(GetRanInt(MIN_LVL, MAX_LVL), siz);
}
DateTime t2 = DateTime.Now;
Console.WriteLine("Objects size 0-{0} bytes : {1} top objects {2:#0.0} million objects in {3:#0.0} seconds = {4:#0.00} million objects/second",
siz, topobj, objcount/1000000.0, (t2-t1).TotalSeconds, objcount/(t2-t1).TotalSeconds/1000000.0);
}
public static void Main(string[] args)
{
Console.WriteLine(Environment.Version);
Test(100);
Test(10000);
}
}
}
Gravatar #9 - arne_v
25. sep. 2010 02:31
Koden postet hvis nogen skulle have lyst til at teste med andre parametre - der er oceaner af muligheder.
Gravatar #10 - arne_v
26. sep. 2010 21:00
mathiass (2) skrev:
Hvis man ikke vil have pauser i sit Java program under udførsel, så har man også en ganske fin mulighed i den indbyggede concurrent garbage collector. Og så ligger objekterne vel at mærke i heapen. Eller er jeg helt gal på den?


Folk har ofte problemer med heap sizes > 10 GB, så det er måske nok lidt mere komplekst end som så.

Der er også en del andre options som kan/bør sættes. Men UseConcMarkSweepGC er den GC i SUN Java som bør give kortest pauser.

BEA (JRockit) kan noget tilsvarende. Og man kan faktisk angive hvor lange pauser man kan leve med.

Har man behov for en ekstrem løsning kan man købe Azul systemer, hvor HW, OS og JVM er integreret til at give optimal performance.

Gå til top

Opret dig som bruger i dag

Det er gratis, og du binder dig ikke til noget.

Når du er oprettet som bruger, får du adgang til en lang række af sidens andre muligheder, såsom at udforme siden efter eget ønske og deltage i diskussionerne.

Opret Bruger Login