SlideShare une entreprise Scribd logo
1  sur  115
Sun JDK 1.6 GC
                               (Garbage Collector)
                                       http://bluedavy.com
                                          2010-05-13 V0.2
                                          2010-05-19 V0.5
                                          2010-06-01 V0.8




ppt中未特别强调的JVM均指Sun JDK 1.6.0
Java:自动内存管理
     为什么还需要学习GC?


   OOM?
   GC成为支撑更高并发量的瓶颈?
only介绍

使用
通常问题查找
Tuning
实现
GC:Garbage Collector

   不是只负责内存回收

   还决定了内存分配
使用
Hotspot是如何分配内存的

Hotspot什么时候回收内存
内存结构
          -Xss

         局部变量区       本地方法栈
PC寄      操作数栈                       -XX:PermSize –

存器         栈帧
                     JVM方法区         XX:MaxPermSize



        JVM方法栈         JVM堆        -Xms -Xmx




备注:在Hotspot中本地方法栈和JVM方法栈是同一个,因此也可用-Xss控制
内存分配
1、堆上分配
  大多数情况在eden上分配,偶尔会直接在old上分配
  细节取决于GC的实现
  这里最重要的优化是TLAB

2、栈上分配
  原子类型的局部变量
  或基于EA后标量替换转变为原子类型的局部变量

3、堆外分配
  DirectByteBuffer
  或直接使用Unsafe.allocateMemory,但不推荐这种方式
内存回收(Garbage Collection)
GC要做的是将那些dead的对象所占用的内存回收掉;

1、Hotspot认为没有引用的对象是dead的

2、Hotspot将引用分为四种
 Strong、Soft、Weak、Phantom
 Strong即默认通过Object o=new Object()这种方式赋值的引用;
 Soft、Weak、Phantom这三种则都是继承Reference;
 在Full GC时会对Reference类型的引用进行特殊处理:
   Soft:内存不够时一定会被GC、长期不用也会被GC,可通过
         -XX:SoftRefLRUPolicyMSPerMB来设置;
   Weak:一定会被GC,当被mark为dead,会在ReferenceQueue
          中通知;
   Phantom:本来就没引用,当从jvm heap中释放,会通知。
内存回收


经IBM研究,通常运行的程序有98%的对象是临时对象,因此
Sun Hotspot对JVM堆采用了分代的方式来管理,以提升GC的
效率。
JVM堆:分代

-Xmn   New Generation

  Eden             S0        S1   Old Generation
         -XX:SurvivorRatio




备注:通常将对新生代进行的回收称为Minor GC;对旧生代进行的回收称为Major GC,但由于
Major GC除并发GC外均需对整个堆进行扫描和回收,因此又称为Full GC。
新生代可用GC
 串行GC                   并行回收GC
              并行GC
 (Serial                 (Parallel
             (ParNew)
Copying)                Scavenge)




           我该用哪个呢?
新生代可用GC—串行
1. client模式下默认GC方式,也可通过-XX:+UseSerialGC来强制指定;

2. eden、s0、s1的大小通过-XX:SurvivorRatio来控制,默认为8,含义
   为eden:s0的比例,启动后可通过jmap –heap [pid]查看。
新生代可用GC—串行
默认情况下,仅在TLAB或eden上分配,只有两种状况会在旧生代分配:
1、需要分配的大小超过eden space大小;
2、在配置了PretenureSizeThreshold的情况下,对象大小大于此值。
 public class SerialGCDemo{
   public static void main(String[] args) throws Exception{
      byte[] bytes=new byte[1024*1024*2];
      byte[] bytes2=new byte[1024*1024*2];
      byte[] bytes3=new byte[1024*1024*2];
      Thread.sleep(3000);
      byte[] bytes4=new byte[1024*1024*4];
      Thread.sleep(3000);
   }
}

             -Xms20M –Xmx20M –Xmn10M –XX:+UseSerialGC

 -Xms20M –Xmx20M –Xmn10M -XX:PretenureSizeThreshold=3145728 –XX:+UseSerialGC
新生代可用GC—串行
当eden space空间不足时触发。

 public class SerialGCDemo{
   public static void main(String[] args) throws Exception{
      byte[] bytes=new byte[1024*1024*2];
      byte[] bytes2=new byte[1024*1024*2];
      byte[] bytes3=new byte[1024*1024*2];
      System.out.println(“step 1");
      byte[] bytes4=new byte[1024*1024*2];
      Thread.sleep(3000);
      System.out.println(“step 2");
      byte[] bytes5=new byte[1024*1024*2];
      byte[] bytes6=new byte[1024*1024*2];
      System.out.println(“step 3");
      byte[] bytes7=new byte[1024*1024*2];
      Thread.sleep(3000);
   }
}


                 -Xms20M –Xmx20M –Xmn10M –XX:+UseSerialGC
新生代可用GC—串行
上面示例之所以会是触发一次minor和一次full,在于Serial GC的这个规则:

在回收前Serial GC会先检测之前每次Minor GC时晋升到旧生代的平均大小是否大
于旧生代的剩余空间,如大于,则直接触发full,如小于,则取决于
HandlePromotionFailure的设置。
新生代可用GC—串行
 public class SerialGCDemo{
   public static void main(String[] args) throws Exception{
      byte[] bytes=new byte[1024*1024*2];
      byte[] bytes2=new byte[1024*1024*2];
      byte[] bytes3=new byte[1024*1024*2];
      System.out.println("step 1");
      bytes=null;
      byte[] bytes4=new byte[1024*1024*2];
      Thread.sleep(3000);
      System.out.println("step 2");
      byte[] bytes5=new byte[1024*1024*2];
      byte[] bytes6=new byte[1024*1024*2];
      bytes4=null;
      bytes5=null;
      bytes6=null;
      System.out.println("step 3");
      byte[] bytes7=new byte[1024*1024*2];
      Thread.sleep(3000);
   }
}


                  -Xms20M –Xmx20M –Xmn10M –XX:+UseSerialGC

       -Xms20M –Xmx20M –Xmn10M -XX:-HandlePromotionFailure –XX:+UseSerialGC
新生代可用GC—串行
上面示例在两个参数时执行效果之所以不同,在于Serial GC的这个规则:

触发Minor GC时:
之前Minor GC晋级到old的平均大小 < 旧生代剩余空间 < eden+from使用空间
当HandlePromotionFailure为true,则仅触发minor gc,如为false,则触发
  full。
新生代可用GC—串行
新生代对象晋升到旧生代的规则

1、经历多次minor gc仍存活的对象,可通过以下参数来控制:
  以MaxTenuringThreshold值为准,默认为15。

2、to space放不下的,直接放入旧生代;
新生代可用GC—串行
public class SerialGCThreshold{                                  -Xms20M –Xmx20M –
  public static void main(String[] args) throws Exception{            Xmn10M –
     SerialGCMemoryObject object1=new SerialGCMemoryObject(1);
     SerialGCMemoryObject object2=new SerialGCMemoryObject(8);
                                                                   XX:+UseSerialGC
     SerialGCMemoryObject object3=new SerialGCMemoryObject(8);
     SerialGCMemoryObject object4=new SerialGCMemoryObject(8);
     object2=null;
     object3=null;
                                                                 -Xms20M –Xmx20M –
     SerialGCMemoryObject object5=new SerialGCMemoryObject(8);        Xmn10M –
     Thread.sleep(4000);                                           XX:+UseSerialGC
     object2=new SerialGCMemoryObject(8);
     object3=new SerialGCMemoryObject(8);                                 -
     object2=null;                                               XX:MaxTenuringThres
     object3=null;
     object5=null;
                                                                       hold=1
     SerialGCMemoryObject object6=new SerialGCMemoryObject(8);
     Thread.sleep(5000);
  }
}
class SerialGCMemoryObject{
  private byte[] bytes=null;
  public SerialGCMemoryObject(int multi){
    bytes=new byte[1024*256*multi];
  }
}
新生代可用GC—串行
把上面代码中的object1修改为如下:
 SerialGCMemoryObject object1=new SerialGCMemoryObject(2);


           -Xms20M –Xmx20M –Xmn10M –XX:+UseSerialGC
新生代可用GC—串行
上面示例中object1在第二次minor gc时直接转入了old,在于Serial GC的
这个规则:

每次Minor GC后会重新计算TenuringThreshold
(第一次以MaxTenuringThreshold为准)

计算的规则为:
累积每个age中的字节,当这个累计值 > To Space的一半时,对比此时的age和
MaxTenuringThreshold,取其中更小的值。

可通过PrintTenuringDistribution来查看下次minor gc时的TenuringThreshold
值:Desired survivor size 524288 bytes, new threshold 1 (max 15),其中
的new threshold 1即为新的TenuringThreshold的值。

例如在上面的例子中:
当第一次Minor GC结束时,遍历age table,当累积age 1的字节后,发现此时所
占用的字节数 > To Space的一半,因此将TenuringThreshold赋值为1,下次
Minor GC时即把age超过1的对象全部转入old。
JVM新生代可用GC—串行
[GC [DefNew: 11509K->1138K(14336K), 0.0110060 secs] 11509K-
  >1138K(38912K),
  0.0112610 secs] [Times: user=0.00 sys=0.01, real=0.01 secs]
新生代可用GC—ParNew
1. CMS GC时默认采用,也可采用-XX:+UseParNewGC强制指定;

2. eden、s0、s1的大小通过-XX:SurvivorRatio来控制,默认为8,含义
   为eden:s0的比例。

默认情况下其内存分配和回收和Serial完全相同,只是回收的时候为多线程
而已,但一旦开启-XX:+UseAdaptiveSizePolicy则有些不同。
新生代可用GC—ParNew
[GC [ParNew: 11509K->1152K(14336K), 0.0129150 secs] 11509K-
  >1152K(38912K),
0.0131890 secs] [Times: user=0.05 sys=0.02, real=0.02 secs]

如启动参数上设置了-XX:+UseAdaptiveSizePolicy,则会输出
[GC [ASParNew: 7495K->120K(9216K), 0.0403410 secs] 7495K-
  >7294K(19456K), 0.0406480 secs] [Times: user=0.06
  sys=0.15, real=0.04 secs]
新生代可用GC—PS
1. server模式时默认的GC方式,也可采用-XX:+UseParallelGC强制指定;

2. eden、s0、s1的大小可通过-XX:SurvivorRatio来控制,但默认情况下
   以-XX:InitialSurivivorRatio为准,此值默认为8,代表的为
   新生代大小 : s0,这点要特别注意。
新生代可用GC—PS
大多数情况下,会在TLAB或eden上分配。

如下一段代码:
 public class PSGCDemo{
   public static void main(String[] args) throws Exception{
      byte[] bytes=new byte[1024*1024*2];
      byte[] bytes2=new byte[1024*1024*2];
      byte[] bytes3=new byte[1024*1024*2];
      Thread.sleep(3000);
      byte[] bytes4=new byte[1024*1024*4];
      Thread.sleep(3000);
   }
}

 -Xms20M –Xmx20M –Xmn10M –XX:SurvivorRatio=8 –XX:+UseParallelGC
新生代可用GC—PS
上面示例中的bytes4之所以会直接在旧生代分配,在于PS GC的这个规则:


当TLAB、eden上分配都失败时,判断需要分配的内存大小是否 >= eden
space的一半大小,如是就直接在旧生代分配。
新生代可用GC—PS
eden space分配不下,且需要分配的对象大小未超过eden space的一半或old区分配失败,
触发回收;

 public class PSGCDemo{
   public static void main(String[] args) throws Exception{
      byte[] bytes=new byte[1024*1024*2];
      byte[] bytes2=new byte[1024*1024*2];
      byte[] bytes3=new byte[1024*1024*2];
      System.out.println(“step 1");
      byte[] bytes4=new byte[1024*1024*2];
      Thread.sleep(3000);
      System.out.println(“step 2");
      byte[] bytes5=new byte[1024*1024*2];
      byte[] bytes6=new byte[1024*1024*2];
      System.out.println(“step 3");
      byte[] bytes7=new byte[1024*1024*2];
      Thread.sleep(3000);
   }
}


  -Xms20M –Xmx20M –Xmn10M –XX:SurvivorRatio=8 –XX:+UseParallelGC
                -XX:+PrintGCDetails –XX:verbose:gc
新生代可用GC—PS
上面示例之所以会是触发一次minor和两次full,在于PS GC的这个规则:

1、在回收前PS GC会先检测之前每次PS GC时晋升到旧生代的平均大小是否大于
  旧生代的剩余空间,如大于,则直接触发full;

2、在回收后,也会按上面规则进行检测。
新生代可用GC—PS
新生代对象晋升到旧生代的规则

1、经历多次minor gc仍存活的对象,可通过以下参数来控制:
  AlwaysTenure,默认false,表示只要minor GC时存活,就晋升到旧生代;
  NeverTenure,默认false,表示永不晋升到旧生代;
  上面两个都没设置的情况下,如UseAdaptiveSizePolicy,启动时以
  InitialTenuringThreshold值作为存活次数的阈值,在每次ps gc后会动态调整
  如不使用UseAdaptiveSizePolicy,则以MaxTenuringThreshold为准。

2、to space放不下的,直接放入旧生代;
新生代可用GC—PS
在回收后,如UseAdaptiveSizePolicy,PS GC会根据运行状况动态调整eden、to
以及TenuringThreshold的大小。
不希望动态调整可设置-XX:-UseAdaptiveSizePolicy。
如希望跟踪每次的变化情况,可在启动参数上增加: PrintAdaptiveSizePolicy
新生代可用GC—PS
[GC [PSYoungGen: 11509K->1184K(14336K)] 11509K-
   >1184K(38912K), 0.0113360 secs]
  [Times: user=0.03 sys=0.01, real=0.01 secs]
旧生代可用的GC
  串行GC          并行 MS GC         并行 Compacting GC       并发GC
(Serial MSC)   (Parallel MSC)   (Parallel Compacting)   (CMS)




                    我该用哪个呢?
旧生代可用GC—串行
client方式下默认GC方式,可通过-XX:+UseSerialGC强制指定。
旧生代可用GC—串行
触发机制
1、old gen空间不足;
2、perm gen空间不足;
3、minor gc时的悲观策略;
4、minor GC后在eden上分配内存仍然失败;
5、执行heap dump时;
6、外部调用System.gc,可通过-XX:+DisableExplicitGC来禁止。


ps: 如CollectGen0First为true(默认为false),则先执行minor GC;
旧生代可用GC—串行
[Full GC [Tenured: 9216K->4210K(10240K), 0.0066570 secs]
   16584K->4210K(19456K), [Perm : 1692K-
   >1692K(16384K)], 0.0067070 secs]
    [Times: user=0.00 sys=0.00, real=0.01 secs]
旧生代可用GC—并行MSC
1. server模式下默认GC方式,可通过-XX:+UseParallelGC强制指定;

2. 并行的线程数
   cpu core<=8 ? cpu core : 3+(cpu core*5)/8
   或通过-XX:ParallelGCThreads=x来强制指定。
旧生代可用GC—并行MSC
触发机制和串行完全相同

ps: 如ScavengeBeforeFullGC为true(默认值),则先执行minor GC;
旧生代可用GC—并行MSC
[Full GC [PSYoungGen: 1208K->0K(8960K)] [PSOldGen: 6144K-
   >7282K(10240K)] 7352K->7282K(19200K) [PSPermGen: 1686K-
   >1686K(16384K)], 0.0165880 secs] [Times: user=0.01
   sys=0.01, real=0.02 secs]
旧生代可用GC—并行Compacting
1. 可通过-XX:+UseParallelOldGC强制指定;

2. 并行的线程数
   cpu core<=8 ? cpu core : 3+(cpu core*5)/8
   或通过-XX:ParallelGCThreads=x来强制指定。
旧生代可用GC—并行Compacting
触发机制和并行MSC完全相同
旧生代可用GC—并行Compacting

[Full GC [PSYoungGen: 1224K->0K(8960K)] [ParOldGen: 6144K-
   >7282K(10240K)] 7368K->7282K(19200K) [PSPermGen: 1686K-
   >1685K(16384K)], 0.0223510 secs] [Times: user=0.02
   sys=0.06, real=0.03 secs]
旧生代可用GC—并发
可通过-XX:+UseConcMarkSweepGC来强制指定,并发的线程数
默认为:( 并行GC线程数+3)/4,也可通过ParallelCMSThreads指定;
旧生代可用GC—并发
触发机制

1、当旧生代空间使用到一定比率时触发;
  JDK V 1.6中默认为92%,可通过PrintCMSInitiationStatistics(此参数在V
  1.5中不能用)来查看这个值到底是多少;
  可通过CMSInitiatingOccupancyFraction来强制指定,默认值并不是赋值在
  了这个值上,是根据如下公式计算出来的:
  ((100 - MinHeapFreeRatio) +(double)(CMSTriggerRatio * MinHeapFreeRatio) / 100.0)/ 100.0;
  MinHeapFreeRatio默认值: 40 CMSTriggerRatio默认值: 80


2、当perm gen采用CMS收集且空间使用到一定比率时触发;
  perm gen采用CMS收集需设置:-XX:+CMSClassUnloadingEnabled
  JDK V 1.6中默认为92%;
  可通过CMSInitiatingPermOccupancyFraction来强制指定,同样,它是根据
  如下公式计算出来的:
  ((100 - MinHeapFreeRatio) +(double)(CMSTriggerPermRatio* MinHeapFreeRatio) / 100.0)/ 100.0;
  MinHeapFreeRatio默认值: 40 CMSTriggerPermRatio默认值: 80
旧生代可用GC—并发
触发机制

3、Hotspot根据成本计算决定是否需要执行CMS GC;
  可通过-XX:+UseCMSInitiatingOccupancyOnly来去掉这个动态执行的策
  略。

4、外部调用了System.gc,且设置了ExplicitGCInvokesConcurrent;
  需要注意,在JDK 6中,在这种情况下如应用同时使用了NIO,可能会出现
  bug。
旧生代可用GC—并发
public class CMSGCOccur{

    public static void main(String[] args) throws Exception{
      byte[] bytes=new byte[1024*1024*2];
       byte[] bytes1=new byte[1024*1024*2];
      byte[] bytes2=new byte[1024*1024*2];
       byte[] bytes3=new byte[1024*1024*1];
       byte[] bytes4=new byte[1024*1024*2];
       Thread.sleep(5000);
    }

}



          -Xms20M –Xmx20M –Xmn10M -XX:+UseConcMarkSweepGC -
           XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintGCDetails

          -Xms20M –Xmx20M –Xmn10M -XX:+UseConcMarkSweepGC -
                          XX:+PrintGCDetails
旧生代可用GC—并发
1. Promotion Failed
   minor GC了,to space空间不够,往old跑,old也满了,so..
   解决方法:增大to space,增大old,或降低cms gc触发时机

2. Concurrent mode failure
   old要分配内存了,但old空间不够,此时cms gc正在进行,so..
   解决方法:增大old,降低cms gc触发的old所占比率。


在这两种情况下,为了安全,JVM转为触发Full GC。
旧生代可用GC—并发
[GC [1 CMS-initial-mark: 13433K(20480K)] 14465K(29696K), 0.0001830 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-mark: 0.004/0.004 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
CMS: abort preclean due to time [CMS-concurrent-abortable-preclean: 0.007/5.042 secs]
[Times: user=0.00 sys=0.00, real=5.04 secs]
[GC[YG occupancy: 3300 K (9216 K)][Rescan (parallel) , 0.0002740 secs]
[weak refs processing, 0.0000090 secs]
[1 CMS-remark: 13433K(20480K)] 16734K(29696K), 0.0003710 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-sweep: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

当在启动参数上设置了-XX:+UseAdaptiveSizePolicy后,上面的日志中的CMS会变为ASCMS



CMS GC Log解读
GC—默认组合

          新生代GC方式   旧生代和持久代GC方式

Client    串行GC      串行GC

Server    并行回收GC    并行 MSC GC(JDK 5.0 Update 6以后)
GC—组合使用
                          新生代GC方式                   旧生代和持久代GC方式

-XX:+UseSerialGC          串行GC                      串行GC
-XX:+UseParallelGC        PS GC                     并行MSC GC
-XX:+UseConcMarkSweepGC   ParNew GC                 并发GC
                                                    当出现concurrent Mode
                                                    failure时采用串行GC

-XX:+UseParNewGC          并行GC                      串行GC
-XX:+UseParallelOldGC     PS GC                     并行Compacting GC



-XX:+UseConcMarkSweepGC   串行GC                      并发GC
-XX:-UseParNewGC                                    当出现Concurrent Mode
                                                    failure或promotion failed
                                                    时则采用串行GC




不支持的组合方式                  1、-XX:+UseParNewGC –XX:+UseParallelOldGC
                          2、-XX:+UseParNewGC –XX:+UseSerialGC
GC方式                        常用参数(-Xms –Xmx –Xmn –XX:PermSize –XX:MaxPermSize)

新生代可用GC       串行GC          -XX:SurvivorRatio,默认为8,代表eden:survivor;
                            -XX:MaxTenuringThreshold,默认为15,代表对象在新生代经历多少次minor gc后才晋升到
                            旧生代;
              PS GC         -XX:InitialSurvivorRatio,默认为8,代表new gen:survivor;
                            -XX:SurvivorRatio,默认值对于PS GC无效,但仍然可设置,代表eden:survivor;
                            -XX:-UseAdaptiveSizePolicy , 不 允 许 PS GC 动 态 调 整 eden 、 s0 、 s1 的 大 小 , 此 时 -
                            XX:MaxTenuringThreshold也可使用;
                            -XX:ParallelGCThreads,设置并行GC的线程数。

              ParNew GC     同串行。

旧生代和持久代可用GC   串行GC          无特殊参数。
              并行GC          -XX:ParallelGCThreads,设置并行GC的线程数。
              (包括MSC、       -XX:+ScavengeBeforeFullGC,Full GC前触发Minor GC
              Compacting)
              并发GC          -XX:ParallelCMSThreads,设置并发CMS GC时的线程数;
                            -XX:CMSInitiatingOccupancyFraction,当旧生代使用比率占到多少百分比时触发CMS GC;
                            -XX:+UseCMSInitiatingOccupancyOnly,默认为false,代表允许hotspot根据成本来决定什么
                            时候执行CMS GC;
                            -XX:+UseCMSCompactAtFullCollection,当Full GC时执行压缩;
                            -XX:CMSMaxAbortablePrecleanTime=5000,设置preclean步骤的超时时间,单位为毫秒;
                            -XX:+CMSClassUnloadingEnabled,Perm Gen采用CMS GC回收。
JVM GC—可见的未来


    Garbage First

       超出范围,以后再扯
通常问题查找
OOM怎么办?

GC怎么监测?

谁耗了内存?
OOM(一些代码造成OOM的例子)
Java Heap OOM产生的原因是在多次gc后仍然分配不了,具体策略取决于这三个
参数:
-XX:+UseGCOverheadLimit   -XX:GCTimeLimit=98 –XX:GCHeapFreeLimit=2

1、OOM的前兆通常体现在每次Full GC后旧生代的消耗呈不断上涨趋势;
  查看方法:jstat –gcutil [pid] [intervel] [count]

2、解决方法
  dump多次Full GC后的内存消耗状况,方法:
  jmap –dump:format=b,file=[filename] [pid]
  dump下来的文件可用MAT进行分析,简单视图分析:MAT Top Consumers

   或在启动参数上增加:-XX:+HeapDumpOnOutOfMemoryError,当OOM
   时会在工作路径(或通过-XX:HeapDumpPath来指定路径)下生成
   java_[pid].hprof文件。

还有Native Heap造成的OOM,堆外内存使用过多。
GC监测
1、jstat –gcutil [pid] [intervel] [count]

2、-verbose:gc // 可以辅助输出一些详细的GC信息
  -XX:+PrintGCDetails // 输出GC详细信息
  -XX:+PrintGCApplicationStoppedTime // 输出GC造成应用暂停的时间
  -XX:+PrintGCDateStamps // GC发生的时间信息
  -XX:+PrintHeapAtGC // 在GC前后输出堆中各个区域的大小
  -Xloggc:[file] // 将GC信息输出到单独的文件中

   gc的日志拿下来后可使用GCLogViewer或gchisto进行分析。

3、图形化的情况下可直接用jvisualvm进行分析。
谁耗了内存
1、对于长期消耗的,好办,直接dump,MAT就一目了然了;

2、对于短期消耗的,比较麻烦,非图形界面暂时还没有什么好办法,图形界面情况
  下可使用jvisualvm的memory profiler或jprofiler。
Tuning
如何做
case 1 – 场景
 4 cpu,os: linux 2.6.18 32 bit
 启动参数
    ◦ -Xms1536M –Xmx1536M –Xmn500M
 系统响应速度大概为100ms;
 当系统QPS增长到40时,机器每隔5秒就执行一
  次minor gc,每隔3分钟就执行一次full gc,并
  且很快就一直full了;
 每次Full gc后旧生代大概会消耗400M,有点多
  了。
case 1 – 目标和方法
   减少Full GC次数,以避免由于GC造成频繁的长
    暂停,从而导致难以支撑高并发量。

   方法
    ◦   降低响应时间或请求次数,这个需要重构,比较麻烦;
    ◦   减少旧生代内存的消耗,比较靠谱;
    ◦   减少每次请求的内存的消耗,貌似比较靠谱;
    ◦   降低GC造成的应用暂停的时间。
case 1 – tuning
   减少旧生代内存的消耗
    ◦ jmap dump;
    ◦ 发现除了一些确实需要在旧生代中消耗的内存外,还有
      点诡异现象;



     可以肯定的是这里面的线程大部分是没有在处理任务的;

     于是根据MAT查找到底谁消耗掉了这些内存;
      ◦ 发现是由于有一个地方使用到了ThreadLocal,但在使用完毕后
      没有去将ThreadLocal.set(null)。
case 1 – tuning
   在做完上面的tuning后,旧生代的内存使用下降
    了大概200M,效果是full gc的频率稍微拖长了
    一点,但仍然不理想,于是旧生代部分无法继续
    优化了;

   想减少每次请求所分配的内存,碰到的巨大问
    题:
    ◦ 怎么才知道呢?貌似没办法
    ◦ 想了一些方法,放弃了。
case 1 – tuning
   降低GC所造成的长暂停
    ◦ 采用CMS GC
    ◦ QPS只能提升到50…

    ◦ 于是放弃,而且还有和jmap –heap的冲突。
case 1 – tuning
   终极必杀技
    ◦ 降低系统响应时间
     QPS终于能支撑到90…
case 2 – 场景
   4 cpu,os: linux 2.6.18 32 bit
   启动参数
    ◦ -server -Xms1536m -Xmx1536m –Xmn700m
   在系统运行到67919.837秒时发生了一次Full GC,日志信息
    如下:
    67919.817: [GC [PSYoungGen: 588706K->70592K(616832K)]
     1408209K->906379K(1472896K),
                 0.0197090 secs] [Times: user=0.06 sys=0.00,
     real=0.02 secs]
    67919.837: [Full GC [PSYoungGen: 70592K->0K(616832K)]
                 [PSOldGen: 835787K->375316K(856064K)]
     906379K->375316K(1472896K)
                 [PSPermGen: 64826K->64826K(98304K)],
     0.5478600 secs]
                 [Times: user=0.55 sys=0.00, real=0.55 secs]
case 2 – 场景
   之后minor gc的信息如下
case 2 – 场景
   在68132.893时又发生了一次Full GC,日志信息如下:
    ◦ 68132.862: [GC [PSYoungGen: 594736K-
      >63715K(609920K)] 1401225K->891090K(1465984K),
                  0.0309810 secs] [Times: user=0.06
      sys=0.01, real=0.04 secs]
    ◦ 68132.893: [Full GC [PSYoungGen: 63715K-
      >0K(609920K)]
                 [PSOldGen: 827375K->368026K(856064K)]
      891090K->368026K(1465984K)
                 [PSPermGen: 64869K-
      >64690K(98304K)], 0.5341070 secs]
                 [Times: user=0.53 sys=0.00, real=0.53
      secs]

   之后的时间的GC基本也在重复上述过程。
case 2 – 目标和方法
   目标
    ◦ 降低full gc的频率,以及gc所造成的应用暂停;
    ◦ 如果在达到上面目标的情况下,还能降低minor gc的
      频率以及所造成的应用暂停时间就好了。

   方法
    ◦ 降低响应时间或请求次数,比较麻烦;
    ◦ 减少每次请求所需分配的内存,貌似比较麻烦;
    ◦ 减少每次minor gc晋升到old的对象,比较靠谱。
case 2 – tuning
   减少每次minor gc晋升到old的对象
    ◦ 调大new,在当前的参数下不好操作;
    ◦ 调大Survivor,根据目前的状况,是可选的方法;
    ◦ 调大TenuringThreshold,根据目前的状况,这不是
      关键点。
case 2 – tuning
   调大Survivor
    ◦ 当前为PS GC方式,Survivor space会被动态调整,有些
      时候会调整的很小,所以导致了经常有对象直接跳到了
      old;
    ◦ 于是不让动态调整了,-XX:-UseAdaptiveSizePolicy
    ◦ 计算Survivor Space需要的大小,简单的计算了下
      看目前的to space的大小,然后minor gc后晋升到old的,
       old+to space的大小作为需要的大小;
      统计多次后做平均;
    ◦ 于是调整…
    ◦ 继续观察,并做微调,保证高峰期以及一定的冗余。
    ◦ 做过这个调整后,效果很明显,minor gc更频繁了些,但
      full的频率推迟到了至少两小时一次。
case 2 – tuning
   上面的tuning达到了降低full gc的目标,但整体GC
    所造成的响应时间下降的仍然不够多,大概只下降了
    10%;

   于是保持Survivor space,同时将GC方式切换为
    CMS GC。
    ◦ -Xms1536m -Xmx1536m -Xmn700m -
      XX:SurvivorRatio=7 -XX:+UseConcMarkSweepGC -
      XX:+UseCMSCompactAtFullCollection -
      XX:CMSMaxAbortablePrecleanTime=1000 -
      XX:+CMSClassUnloadingEnabled -
      XX:+UseCMSInitiatingOccupancyOnly -
      XX:+DisableExplicitGC
GC Tuning
           1、评估现状



  5、细微调整            2、设定目标




    4、衡量调优    3、尝试调优
GC Tuning—衡量现状
1. 衡量工具
   -XX:+PrintGCDetails –XX:+PrintGCApplicationStoppedTime
   -Xloggc: {文件名} –XX:+PrintGCTimeStamps
   jmap(由于每个版本jvm的默认值可能会有改变,建议还是用jmap
   首先观察下目前每个代的内存大小、GC方式)
   jstat、jvisualvm、sar 、gclogviewer 
   系统运行状况的监测工具

2. 应收集到的信息
   minor gc多久执行一次,full gc多久执行一次,每次耗时多少?
   高峰期什么状况?
   minor gc时回收的效果如何,survivor的消耗状况如何,每次有
   多少对象会进入old?
   old区在full gc后会消耗多少(简单的memory leak判断方法)
   系统的load、cpu消耗、qps or tps、响应时间
GC Tuning—设定目标
调优的目标是什么呢

 降低Full GC执行频率?

 降低Full GC消耗时间?

 降低Full GC所造成的应用暂停时间?

 降低Minor GC执行频率?

 降低Minor GC消耗时间?

 例如某系统的GC调优目标:
 降低Full GC执行频率的同时,尽可能降低minor GC的执行频率、
 消耗时间以及GC对应用造成的暂停时间。
GC Tuning—尝试调优
根据目标针对性的寻找瓶颈以及制定调优策略

 来说说常见的

 降低Full GC执行频率
  根据前面学习到的Full GC触发时机,寻找到瓶颈
   为什么Full GC执行频率高呢,old经常满?还是old本来占用就高呢?
   old为什么经常满呢?请参见PPT前面的内容...
   是不是因为minor gc后经常有对象进入old呢?为什么?


 注意Java RMI的定时GC触发,可通过:
 -XX:+DisableExplicitGC来禁止;
 或通过 -Dsun.rmi.dgc.server.gcInterval=3600000来控制触发的时间。
GC Tuning—尝试调优
降低Full GC执行频率 – 通常瓶颈

 Old本身占用的就一直高,所以只要稍微放点对象到old,就full了;
    通常原因:缓存的东西太多
         oracle 10g驱动时preparedstatement cache太大

   查找办法,很简单:dump        then mat,bingo!
GC Tuning—尝试调优
降低Full GC执行频率 – 通常瓶颈


 Minor GC后总是有对象不断的进入Old,导致Old不断的满

   通常原因:Survivor太小了
        系统响应太慢、请求量太大、每次请求分配内存多
        分配的对象太大...

   查找办法:dump这时就不是很好用了,需要的是能分析两次
         minor GC之间到底哪些地方分配了内存;

          jstat观察Survivor的消耗状况,-XX:PrintHeapAtGC
           输出GC前后的详细信息;

          系统响应慢那行属于系统优化,不在这里扯;
GC Tuning—尝试调优
降低Full GC执行频率 – 调优策略
 Old本身占用的就一直高

    调优办法
     ① 扩大old大小(减少new或调大heap);
       减少new注意对minor gc的影响并且同时有可能造成full
       gc还是严重;
       调大heap注意full gc的时间的延长,cpu够强悍嘛,os
       32 bit的吗?

      ② 程序优化(去掉一些不必要的缓存)
GC Tuning—尝试调优
降低Full GC执行频率 – 调优策略
 Minor GC后总是有对象不断的进入Old
    前提:这些进入Old的对象在full时大部分都会被回收
     调优办法
        ① 降低Minor GC执行频率(等到那部分再讲)

     ② 让对象尽量在Minor GC中就被回收掉
       放大new、放大survivor、增大TenuringThreshold
       但要注意这些有可能会造成minor gc执行频繁

     ③ 换CMS GC
       Old还没满就回收掉,从而降低Full GC触发的可能
     ④ 程序优化
       提升响应速度、降低每次请求分配的内存
GC Tuning—尝试调优
降低单次Full GC执行时间

 通常原因:
   旧生代太大了...

 通常办法:
   是并行GC吗?
   加点CPU吧
   升级CPU吧
   减小Heap或旧生代吧
GC Tuning—尝试调优
降低Minor GC执行频率

 通常原因:
   每次请求分配的内存多、请求量大

 通常办法:
  扩大heap、扩大新生代、扩大eden,扩大时请综合考虑;
  降低每次请求分配的内存;
  加机器吧,分担点请求量。
GC Tuning—尝试调优
降低Minor GC执行时间

 通常原因:
   新生代太大了
   响应速度太慢了,导致每次Minor GC时存活的对象多

 通常办法:
   减小点新生代吧;
   加点CPU吧、升级CPU吧;
   响应能不能快点呢?
GC Tuning—算命

① 当响应速度下降到多少、或请
  求量上涨到多少时,系统会
  挂掉?

② 参数调整后系统多久会执行一
 次Minor,多久会执行一次
 Full,高峰期会如何?
GC Tuning—不是瞎算的
① 系统的生辰八字
 每次请求平均需要分配多少内存?
 系统的平均响应时间是多少呢?
 请求量是多少、多久一次Minor、Full?

② 先掐指算下
 在现在的参数下,应该是多久一次
 Minor、Full,对比真实状况,做一定
 的偏差;

③ 根据所掌握的知识,就可以判断了
GC Tuning—来算一卦
GC Tuning—总结

        是个复杂过程,按照Tony(GC主要作者的
        说法):GC Tuning is art!

        综合考虑,每个参数的调整都有可能带来
        其他的影响。

        总结来说,提升响应速度、降低每次请求
        分配的内存才是必杀技!
        或者不计成本:64 bit,多个高档CPU、
        大量的内存都上!
实现
Hotspot GC是如何实现的
内存回收
1、通常有两种实现方法:
  1.1 引用计数
      不适合复杂对象引用关系,尤其是有循环依赖的场景;
      需要计数;
      优点是只要计数器降为0,就可被回收。

 1.2 跟踪(有向图Tracing)
     适合于复杂对象引用关系场景,Hotspot采用这种;
     需要到达某个时机后触发执行,并且通常需要暂停应用线程。
     常用算法:Copying、Mark-Sweep、Mark-Compact,算法请
     参见《垃圾回收》这本绝版书。
内存回收
Hotspot从root set开始扫描有引用的对象,并对Reference类型的对象特殊
处理。

root set
1、当前正在执行的线程;
2、全局/静态变量;
3、JVM Handles;
4、JNI Handles;
内存回收
如何暂停应用线程?

 safepoint first: 检测某内存页是否可读的指令

 先想想:只有会改变引用关系的地方才需要暂停,否则没必要,因此对于
 正在native中执行的线程,JVM是不管的,而当native代码需要改变引用
 关系时,又回到了hotspot java部分的代码,而在那些代码上是会有
 safepoint的。

 代码编译时会在某些部分生成safepoint,当需要GC时,GC会向core vm
 提交暂停应用线程的请求,core vm会将safepoint检测的内存页置为
 不可读状态,当解释执行或JIT编译执行到safepoint时,发现内存页不可
 读,于是就挂起了。
新生代可用GC
 串行GC                   并行回收GC
              并行GC
 (Serial                 (Parallel
             (ParNew)
Copying)                Scavenge)
新生代可用GC
在分配时均采用连续空间和bump the pointer的方式。




    A   B   C   D
新生代可用GC
在回收时均采用如下策略:

 扫描新生代,找出其中
 活的对象;
 基于Copying算法回收,
 新生代中活的对象在回收
 时会根据一定的规则晋升
 到旧生代。
新生代可用GC
由于只扫描新生代,如旧生代的对象引用了新生代的,怎么办?

 在给对象赋引用时,会经过一个write barrier;

 检查是否为旧生代引用新生代,如为则记录到remember set中;

 在minor gc时,remember set指向的新生代对象也作为root set。
新生代可用GC—串行
完整内存分配策略
1、首先在tlab上尝试分配;
2、检查是否需要在new上分配,如需要分配的大小小于
  PretenureSizeThreshold,则在eden上进行分配,分配成功则返回,
  分配失败则继续;
3、检查是否需要尝试在旧生代上分配,如需要,则遍历所有代,并检查是
  否可在该代上分配,如可以则进行分配;如不需要在旧生代上尝试分配,
  那么则检查是否可以在eden上分配,如可以则分配,
  否则则尝试在old上分配;
4、根据策略决定执行新生代GC或Full GC,执行full gc时不清除soft Ref;
5、如需要分配的大小大于PretenureSizeThreshold,尝试在old上分配,
  否则尝试在eden上分配;
6、尝试扩大堆并分配;
7、执行full gc,并清除所有soft Ref,按步骤5继续尝试分配。
新生代可用GC—串行
完整内存回收策略

1、检查to是否为空,不为空返回false;
2、检查old剩余空间是否大于当前eden+from已用的大小,如大于则返回true,
  如小于且HandlePromotionFailure为true,则检查剩余空间是否大于之前每次
  minor gc晋级到old的平均大小,如大于返回true,如小于返回false。
3、如上面的结果为false,则执行full gc,如上面的结果为true,执行下面的步
  骤;
4、扫描引用关系,将活的对象copy到to space,如对象在minor gc中的存活次数
  超过tenuring_threshold或分配失败,则往旧生代复制,如仍然复制失败,则
  取决于HandlePromotionFailure,如不需要处理,直接抛出OOM,并退出
  vm,如需处理,则保持这些新生代对象不动;
新生代可用GC—ParNew
内存分配策略和串行方式完全相同。
新生代可用GC—ParNew
内存回收策略

策略和串行相同,只是回收转为了多线程方式。
新生代可用GC—PS
完整内存分配策略
 1、先在TLAB上分配,分配失败则直接在eden上分配;
  2、当eden上分配失败时,检查需要分配的大小是否 >= eden space
    的一半,如是,则直接在旧生代分配;
  3、如分配仍然失败,且gc已超过频率,则抛出OOM;
  4、进入基本分配策略失败的模式;
  5、执行PS GC,在eden上分配;
  6、执行非最大压缩的full gc,在eden上分配;
  7、在旧生代上分配;
  8、执行最大压缩full gc,在eden上分配;
  9、在旧生代上分配;
 10、如还失败,回到2。

最悲惨的情况,分配触发多次PS GC和多次Full GC,直到OOM。
新生代可用GC—PS
完整内存回收策略
1、如gc所执行的时间超过,直接结束;
2、先调用invoke_nopolicy
 2.1 先检查是不是要尝试scavenge;
   2.1.1 to space必须为空,如不为空,则返回false;
   2.1.2 获取之前所有minor gc晋级到old的平均大小,并对比目前
          eden+from已使用的大小,取更小的一个值,如old剩余空间
        小于此值,则返回false,如大于则返回true;
 2.2 如不需要尝试scavenge,则返回false,否则继续;
 2.3 多线程扫描活的对象,并基于copying算法回收,回收时相应的晋升对象到旧生代;
 2.4 如UseAdaptiveSizePolicy,那么重新计算to space和
     tenuringThreshold的值,并调整。
3、如invoke_nopolicy返回的是false,或之前所有minor gc晋级到old的
   平均大小 > 旧生代的剩余空间,那么继续下面的步骤,否则结束;
4、如UseParallelOldGC,则执行PSParallelCompact,如不是
   UseParallelOldGC,则执行PSMarkSweep。
旧生代可用的GC
  串行GC          并行 MSC GC        并行 Compacting GC       并发GC
(Serial MSC)   (Parallel MSC)   (Parallel Compacting)   (CMS)
旧生代可用GC—串行
内存分配策略

1、不支持TLAB;

2、bump pointer的分配方式。
旧生代可用GC—串行
内存回收策略

1、基于Mark Sweep Compact实现;
2、如CollectGen0First为true(默认为false),则先执行minor GC;

回收过程分为四个阶段完成:
1、标记哪些对象是活的;
2、计算新的地址;
3、更新指针指向新的地址;
4、将对象移到新的地址。
旧生代可用GC—并行MSC
内存分配策略

1、在旧生代上按照bump pointer机制进行分配;

2、分配不了的情况下尝试等待几毫秒(通过以下参数设置)后再分配;
  GCExpandToAllocateDelayMillis,默认为0

3、再分配不了就返回NULL。
旧生代可用GC—并行MSC
内存回收基于Mark Sweep Compact实现。

四个阶段:
1、标记活的对象;
2、计算这些活的对象新的目标地址;
3、更新指针指向新的地址;
4、移动对象到新的地址。
旧生代可用GC—并行Compacting
内存分配策略和并行MS相同。
旧生代可用GC—并行Compacting
内存回收基于Mark Compact实现,图示如下:
旧生代可用GC—并发
内存分配策略

1、首先要拿到freelist锁;
2、找到可以容纳下对象大小的chunk,然后分配;
3、如目前正在marking阶段,那么将此新分配的对象标识为活的。
旧生代可用GC—并发
1. 系统启动时在后台启动一个CMS线程,定时检查是否需要触发CMS GC

2. 基于Mark-Sweep实现;
   Initial Marking(Stop-the-world)
   Concurrent Marking
   PreClean(Sun HotSpot 1.5后引入的优化步骤)
   Final Marking (Stop-the-world)
   Concurrent Sweeping
旧生代可用GC—并发
1. Initial Marking(Stop-the-world)
      mark下root set直接引用的对象

2. Concurrent Marking
     并发标识上面mark出来的对象的引用;
     Mod Union Table
       Minor GC同时进行,有可能会导致旧生代引用的对象关系改变
     Card Table
       旧生代中的对象引用关系也有可能改变
旧生代可用GC—并发
3. Preclean
      重新扫描上一步过程中新创建的对象和引用关系改变了的对象的引
      用关系;
      此步什么时候执行,以及执行到什么时候再触发后续动作,取决于
      两个值:-XX: CMSScheduleRemarkEdenSizeThreshold、
            -XX: CMSScheduleRemarkEdenPenetration
      第一个值默认为2,第二个值默认为50%,代表着当eden space
      使用超过2M时,执行此步,当使用超过50%时,触发remark;

    上面这个步骤有些时候有可能会引发bug,有对象需要在old分配
    空间,但由于remark总是没执行,导致old空间不足,默认此步的
    超时时间为5秒,可通过-XX: CMSMaxAbortablePrecleanTime
    设置,单位为毫秒。
旧生代可用GC—并发
4. Final Marking(Stop-the-world)
   处理Mod Union Table和Card Table中dirty的对象,重新mark。

5. Concurrent Sweeping
   并发回收。
旧生代可用GC—并发
优缺点

1. 大部分时候和应用并发进行,因此只会造成很短的暂停时间;

2. 浮动垃圾,没办法,so内存空间要稍微大一点;

3. 内存碎片,-XX:+UseCMSCompactAtFullCollection 来解决;

4. 争抢CPU,这GC方式就这样;

5. 多次remark,所以总的gc时间会比并行的长;

6. 内存分配,free list方式,so性能稍差,对minor GC会有一点影响;

7. 和应用并发,有可能分配和回收同时,产生竞争,引入了锁,JVM分配
   优先。
旧生代可用GC—并发
  浮动垃圾 产生于card table
References
1、GC Tuning in the Hotspot
2、Our Collectors
3、CMS GC
4、why now
5、JDK 6.0 gc tuning
6、memory management in hotspot whitepaper
7、JVM内存管理和垃圾回收

Contenu connexe

Tendances

【Maclean liu技术分享】深入理解oracle中mutex的内部原理
【Maclean liu技术分享】深入理解oracle中mutex的内部原理【Maclean liu技术分享】深入理解oracle中mutex的内部原理
【Maclean liu技术分享】深入理解oracle中mutex的内部原理
maclean liu
 
前端本地应用程序网络
前端本地应用程序网络前端本地应用程序网络
前端本地应用程序网络
tblanlan
 
服务器端性能优化 提升Qps、rt
服务器端性能优化 提升Qps、rt服务器端性能优化 提升Qps、rt
服务器端性能优化 提升Qps、rt
锐 张
 
Tokyo Cabinet Key Value数据库及其扩展应用
Tokyo Cabinet  Key Value数据库及其扩展应用Tokyo Cabinet  Key Value数据库及其扩展应用
Tokyo Cabinet Key Value数据库及其扩展应用
rewinx
 
我对后端优化的一点想法.pptx
我对后端优化的一点想法.pptx我对后端优化的一点想法.pptx
我对后端优化的一点想法.pptx
james tong
 

Tendances (18)

Mongo db at qihoo 360
Mongo db at qihoo 360Mongo db at qihoo 360
Mongo db at qihoo 360
 
Jvm那些事
Jvm那些事Jvm那些事
Jvm那些事
 
【Maclean liu技术分享】深入理解oracle中mutex的内部原理
【Maclean liu技术分享】深入理解oracle中mutex的内部原理【Maclean liu技术分享】深入理解oracle中mutex的内部原理
【Maclean liu技术分享】深入理解oracle中mutex的内部原理
 
前端本地应用程序网络
前端本地应用程序网络前端本地应用程序网络
前端本地应用程序网络
 
服务器端性能优化 提升Qps、rt
服务器端性能优化 提升Qps、rt服务器端性能优化 提升Qps、rt
服务器端性能优化 提升Qps、rt
 
可靠分布式系统基础 Paxos的直观解释
可靠分布式系统基础 Paxos的直观解释可靠分布式系统基础 Paxos的直观解释
可靠分布式系统基础 Paxos的直观解释
 
分布式系统缓存设计
分布式系统缓存设计分布式系统缓存设计
分布式系统缓存设计
 
分布式系统缓存设计
分布式系统缓存设计分布式系统缓存设计
分布式系统缓存设计
 
图解分布式一致性协议Paxos 20150311
图解分布式一致性协议Paxos 20150311图解分布式一致性协议Paxos 20150311
图解分布式一致性协议Paxos 20150311
 
Storm
StormStorm
Storm
 
Jvm内存管理基础
Jvm内存管理基础Jvm内存管理基础
Jvm内存管理基础
 
Tokyo Cabinet Key Value数据库及其扩展应用
Tokyo Cabinet  Key Value数据库及其扩展应用Tokyo Cabinet  Key Value数据库及其扩展应用
Tokyo Cabinet Key Value数据库及其扩展应用
 
Java Crash分析(2012-05-10)
Java Crash分析(2012-05-10)Java Crash分析(2012-05-10)
Java Crash分析(2012-05-10)
 
我对后端优化的一点想法.pptx
我对后端优化的一点想法.pptx我对后端优化的一点想法.pptx
我对后端优化的一点想法.pptx
 
Optimzing mysql
Optimzing mysqlOptimzing mysql
Optimzing mysql
 
Os讀書會20170518
Os讀書會20170518Os讀書會20170518
Os讀書會20170518
 
Effective linux.3.(diagnosis)
Effective linux.3.(diagnosis)Effective linux.3.(diagnosis)
Effective linux.3.(diagnosis)
 
微博实时搜索
微博实时搜索微博实时搜索
微博实时搜索
 

En vedette

Lamp高性能设计
Lamp高性能设计Lamp高性能设计
Lamp高性能设计
锐 张
 
Openstack starter-guide-diablo
Openstack starter-guide-diabloOpenstack starter-guide-diablo
Openstack starter-guide-diablo
锐 张
 
长尾理论(The longtail)版
长尾理论(The longtail)版长尾理论(The longtail)版
长尾理论(The longtail)版
锐 张
 
Redis内存存储结构分析
Redis内存存储结构分析Redis内存存储结构分析
Redis内存存储结构分析
锐 张
 
新浪云计算公开课第二期:Sae平台的灵活应用(吕毅、魏世江)
新浪云计算公开课第二期:Sae平台的灵活应用(吕毅、魏世江)新浪云计算公开课第二期:Sae平台的灵活应用(吕毅、魏世江)
新浪云计算公开课第二期:Sae平台的灵活应用(吕毅、魏世江)
锐 张
 
Redis深入浅出
Redis深入浅出Redis深入浅出
Redis深入浅出
锐 张
 

En vedette (7)

Lamp高性能设计
Lamp高性能设计Lamp高性能设计
Lamp高性能设计
 
Openstack starter-guide-diablo
Openstack starter-guide-diabloOpenstack starter-guide-diablo
Openstack starter-guide-diablo
 
长尾理论(The longtail)版
长尾理论(The longtail)版长尾理论(The longtail)版
长尾理论(The longtail)版
 
Redis内存存储结构分析
Redis内存存储结构分析Redis内存存储结构分析
Redis内存存储结构分析
 
新浪云计算公开课第二期:Sae平台的灵活应用(吕毅、魏世江)
新浪云计算公开课第二期:Sae平台的灵活应用(吕毅、魏世江)新浪云计算公开课第二期:Sae平台的灵活应用(吕毅、魏世江)
新浪云计算公开课第二期:Sae平台的灵活应用(吕毅、魏世江)
 
Our heroes
Our heroesOur heroes
Our heroes
 
Redis深入浅出
Redis深入浅出Redis深入浅出
Redis深入浅出
 

Similaire à Sun jdk-1.6-gc

Sun jdk 1.6内存管理 -使用篇
Sun jdk 1.6内存管理 -使用篇Sun jdk 1.6内存管理 -使用篇
Sun jdk 1.6内存管理 -使用篇
bluedavy lin
 
Sun jdk 1.6内存管理 -使用篇-毕玄
Sun jdk 1.6内存管理 -使用篇-毕玄Sun jdk 1.6内存管理 -使用篇-毕玄
Sun jdk 1.6内存管理 -使用篇-毕玄
锐 张
 
Java垃圾收集原理
Java垃圾收集原理Java垃圾收集原理
Java垃圾收集原理
yin gong
 
淘宝前端优化
淘宝前端优化淘宝前端优化
淘宝前端优化
锐 张
 
Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)
FLASH开发者交流会
 
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
Shanda innovation institute
 
基于Innodb开发的最佳实践
基于Innodb开发的最佳实践基于Innodb开发的最佳实践
基于Innodb开发的最佳实践
wubx
 
Java线上应用问题排查方法和工具(空望)
Java线上应用问题排查方法和工具(空望)Java线上应用问题排查方法和工具(空望)
Java线上应用问题排查方法和工具(空望)
ykdsg
 

Similaire à Sun jdk-1.6-gc (20)

Sun jdk 1.6内存管理 -使用篇
Sun jdk 1.6内存管理 -使用篇Sun jdk 1.6内存管理 -使用篇
Sun jdk 1.6内存管理 -使用篇
 
Java内存管理问题案例分享
Java内存管理问题案例分享Java内存管理问题案例分享
Java内存管理问题案例分享
 
Golang advance
Golang advanceGolang advance
Golang advance
 
实战HotSpot JVM GC
实战HotSpot JVM GC实战HotSpot JVM GC
实战HotSpot JVM GC
 
Jvm内存问题最佳实践
Jvm内存问题最佳实践Jvm内存问题最佳实践
Jvm内存问题最佳实践
 
Sun jdk 1.6内存管理 -使用篇-毕玄
Sun jdk 1.6内存管理 -使用篇-毕玄Sun jdk 1.6内存管理 -使用篇-毕玄
Sun jdk 1.6内存管理 -使用篇-毕玄
 
Java垃圾收集原理
Java垃圾收集原理Java垃圾收集原理
Java垃圾收集原理
 
Lab2
Lab2Lab2
Lab2
 
淘宝前端优化
淘宝前端优化淘宝前端优化
淘宝前端优化
 
MIUI Dump Bitmap Tool 介绍
MIUI Dump Bitmap Tool 介绍MIUI Dump Bitmap Tool 介绍
MIUI Dump Bitmap Tool 介绍
 
MongoDB at Qihoo 360
MongoDB at Qihoo 360MongoDB at Qihoo 360
MongoDB at Qihoo 360
 
Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)
 
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
 
Gdb principle
Gdb principleGdb principle
Gdb principle
 
Aswan&hump
Aswan&humpAswan&hump
Aswan&hump
 
基于Innodb开发的最佳实践
基于Innodb开发的最佳实践基于Innodb开发的最佳实践
基于Innodb开发的最佳实践
 
Java线上应用问题排查方法和工具(空望)
Java线上应用问题排查方法和工具(空望)Java线上应用问题排查方法和工具(空望)
Java线上应用问题排查方法和工具(空望)
 
快快樂樂SIMD
快快樂樂SIMD快快樂樂SIMD
快快樂樂SIMD
 
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
 
基于Gpu的高性能计算
基于Gpu的高性能计算基于Gpu的高性能计算
基于Gpu的高性能计算
 

Plus de 锐 张

基于My sql的分布式数据库实践
基于My sql的分布式数据库实践基于My sql的分布式数据库实践
基于My sql的分布式数据库实践
锐 张
 
Redis中文入门手册
Redis中文入门手册Redis中文入门手册
Redis中文入门手册
锐 张
 
Redis学习笔记
Redis学习笔记Redis学习笔记
Redis学习笔记
锐 张
 
Sun jdk 1.6内存管理 -实现篇 -毕玄
Sun jdk 1.6内存管理 -实现篇 -毕玄Sun jdk 1.6内存管理 -实现篇 -毕玄
Sun jdk 1.6内存管理 -实现篇 -毕玄
锐 张
 
Sun jdk 1.6内存管理 -调优篇-毕玄
Sun jdk 1.6内存管理 -调优篇-毕玄Sun jdk 1.6内存管理 -调优篇-毕玄
Sun jdk 1.6内存管理 -调优篇-毕玄
锐 张
 
Redis介绍
Redis介绍Redis介绍
Redis介绍
锐 张
 
Green plum培训材料
Green plum培训材料Green plum培训材料
Green plum培训材料
锐 张
 
Greenplum技术
Greenplum技术Greenplum技术
Greenplum技术
锐 张
 
新时代的分析型云数据库 Greenplum
新时代的分析型云数据库 Greenplum新时代的分析型云数据库 Greenplum
新时代的分析型云数据库 Greenplum
锐 张
 
新浪云计算公开课第一期:Let’s run @ sae(丛磊)
新浪云计算公开课第一期:Let’s run @ sae(丛磊)新浪云计算公开课第一期:Let’s run @ sae(丛磊)
新浪云计算公开课第一期:Let’s run @ sae(丛磊)
锐 张
 
亚马逊云计算Aws
亚马逊云计算Aws亚马逊云计算Aws
亚马逊云计算Aws
锐 张
 
20110625.【打造高效能的cdn系统】.易统
20110625.【打造高效能的cdn系统】.易统20110625.【打造高效能的cdn系统】.易统
20110625.【打造高效能的cdn系统】.易统
锐 张
 
网易海量数据存储平台的构建和运维
网易海量数据存储平台的构建和运维网易海量数据存储平台的构建和运维
网易海量数据存储平台的构建和运维
锐 张
 
09 赵昆
09 赵昆09 赵昆
09 赵昆
锐 张
 
07 丛磊
07 丛磊07 丛磊
07 丛磊
锐 张
 
05 杨志丰
05 杨志丰05 杨志丰
05 杨志丰
锐 张
 
人人网互联网产品易用性、Ue设计培训
人人网互联网产品易用性、Ue设计培训人人网互联网产品易用性、Ue设计培训
人人网互联网产品易用性、Ue设计培训
锐 张
 
C2c网站运营ppt
C2c网站运营pptC2c网站运营ppt
C2c网站运营ppt
锐 张
 
Big pipe backend2
Big pipe backend2Big pipe backend2
Big pipe backend2
锐 张
 
数据成就互联网的可能 用技术撬动Roi-好耶
数据成就互联网的可能 用技术撬动Roi-好耶数据成就互联网的可能 用技术撬动Roi-好耶
数据成就互联网的可能 用技术撬动Roi-好耶
锐 张
 

Plus de 锐 张 (20)

基于My sql的分布式数据库实践
基于My sql的分布式数据库实践基于My sql的分布式数据库实践
基于My sql的分布式数据库实践
 
Redis中文入门手册
Redis中文入门手册Redis中文入门手册
Redis中文入门手册
 
Redis学习笔记
Redis学习笔记Redis学习笔记
Redis学习笔记
 
Sun jdk 1.6内存管理 -实现篇 -毕玄
Sun jdk 1.6内存管理 -实现篇 -毕玄Sun jdk 1.6内存管理 -实现篇 -毕玄
Sun jdk 1.6内存管理 -实现篇 -毕玄
 
Sun jdk 1.6内存管理 -调优篇-毕玄
Sun jdk 1.6内存管理 -调优篇-毕玄Sun jdk 1.6内存管理 -调优篇-毕玄
Sun jdk 1.6内存管理 -调优篇-毕玄
 
Redis介绍
Redis介绍Redis介绍
Redis介绍
 
Green plum培训材料
Green plum培训材料Green plum培训材料
Green plum培训材料
 
Greenplum技术
Greenplum技术Greenplum技术
Greenplum技术
 
新时代的分析型云数据库 Greenplum
新时代的分析型云数据库 Greenplum新时代的分析型云数据库 Greenplum
新时代的分析型云数据库 Greenplum
 
新浪云计算公开课第一期:Let’s run @ sae(丛磊)
新浪云计算公开课第一期:Let’s run @ sae(丛磊)新浪云计算公开课第一期:Let’s run @ sae(丛磊)
新浪云计算公开课第一期:Let’s run @ sae(丛磊)
 
亚马逊云计算Aws
亚马逊云计算Aws亚马逊云计算Aws
亚马逊云计算Aws
 
20110625.【打造高效能的cdn系统】.易统
20110625.【打造高效能的cdn系统】.易统20110625.【打造高效能的cdn系统】.易统
20110625.【打造高效能的cdn系统】.易统
 
网易海量数据存储平台的构建和运维
网易海量数据存储平台的构建和运维网易海量数据存储平台的构建和运维
网易海量数据存储平台的构建和运维
 
09 赵昆
09 赵昆09 赵昆
09 赵昆
 
07 丛磊
07 丛磊07 丛磊
07 丛磊
 
05 杨志丰
05 杨志丰05 杨志丰
05 杨志丰
 
人人网互联网产品易用性、Ue设计培训
人人网互联网产品易用性、Ue设计培训人人网互联网产品易用性、Ue设计培训
人人网互联网产品易用性、Ue设计培训
 
C2c网站运营ppt
C2c网站运营pptC2c网站运营ppt
C2c网站运营ppt
 
Big pipe backend2
Big pipe backend2Big pipe backend2
Big pipe backend2
 
数据成就互联网的可能 用技术撬动Roi-好耶
数据成就互联网的可能 用技术撬动Roi-好耶数据成就互联网的可能 用技术撬动Roi-好耶
数据成就互联网的可能 用技术撬动Roi-好耶
 

Sun jdk-1.6-gc