Thinking in java-4 Java内存管理之垃圾回收Garbage Collection

1. 垃圾回收机制

1. 自动垃圾回收

Java编程语言的一个特色就是其自动垃圾回收机制,不像C/C++那样,内存的分配和释放都是程序员手动操作的。

2. What?

Garbage Collector垃圾回收器,是在后台运行的程序,它照看所有内存中的对象,找到没被程序中任何其他部分所引用的对象。所有这些未被引用的对象被删除,其空间被释放用来分配给其他对象。

3. 垃圾回收步骤

垃圾回收一般包括三个基本步骤:

  • 标记--Marking
这是 垃圾回收的第一步,这里垃圾回收器辨认哪些对象在使用中,哪些对象没有被使用。
  • 常规删除--Normal Deletion
垃圾回收器删除未被使用的对象,并将对象所占的空间释放。
  • 有紧致效果的删除--Deletion with Compacting
为了更好的性能,垃圾回收器在删除了未被使用的对象后,所有幸存的对象将被移动到一起。这将提高分配给新对象内存的性能。

4. 问题和对策

问题:这种基本的标记和删除--Mark and delete的方式存在以下问题:
  a. 首先,因为绝大部分新创建的对象将会变得不可用而成为垃圾,这是其效率低的一个原因;
b. 其次,在多个垃圾回收周期中被使用的对象,很可能在未来的周期依然被使用。
对策:内存分代。
因为存在上述的问题,所以我们采用了Java Garbage Collection is Generational,我们在内存上分为Young Generation 和 Old Generation.
所以Heap内存的是分为Young Generation/Old Generation; Heap内存的回收也是分为 Minor GC和Major GC。

2. 垃圾回收策略

共有5种垃圾回收类型,我们可以在应用中使用。我们只需使用JVM switch来选取给定的策略。
    1).Serial GC(-XX:+UseSerialGC): 串行GC使用的是简单的mark-sweep-compact策略来处理年轻带和老年代的垃圾回收,也就是所谓的Minor GC和 Major GC。
串行GC对于用户机来说是有效的,这些客户机运行的是独立的应用,并有很小的CPU。这种策略适用于内存需求小的小型应用。
2).Parallel GC(-XX:+UseParallelGC):
并行GC除了它产生N个线程对应于年轻代的垃圾回收(这里N对应于系统中CPU的核数),基本和串行GC相同。我们可以通过控制线程数量使用:-XX:ParallelGCThreads=n JVM选项来调整。
并行GC也被称作Throughout collector(吞吐量垃圾回收器),因为它使用了多个CPU加速了GC的性能。并行GC使用的是单线程控制老年代的垃圾回收。
3).Parallel Old GC(-XX:+UseParallelOldGC):和Parallel GC相同,除了其对于老年代的内存回收也使用了多线程处理之外。
4).Concurrent Mark Sweep(CMS)(-XX:+UseConcMarkSweepGC): CMS 垃圾回收器,也被称作“并发低暂停”垃圾回收器。这里的并发主要对应的是老年代。CMS collector试图通过最小化垃圾回收所带来的延迟,通过并发地和应用线程一起执行来解决。
CMS collector 所用的年轻带的算法和并行GC相同。
这种垃圾回收算法适用于需要高度响应的我们无法忍受长时间等待的系统中。我们可以通过下列参数控制CMS collector线程的数量:-XX:ParallelCMSThreads=n.
5).G1 Garbage Collector(-XX:+UseG1GC):Garbage First或者叫G1 garbage collector。这种策略从Java 7开始可用,它的长期目标是取代现有的CMS collector。G1 garbage collector 是一种并行的、并发的、内存紧致、低延迟的垃圾回收器。
G1垃圾回收器和其他垃圾回收器不同,而且没有年轻带和老年代的概念。它把堆内存分成了多个大小相同的堆区域。当垃圾回收器开始工作时,首先把区域中具有更少存活数据的区域收集起来,这就是所谓的“Garbage First”--垃圾第一。

3. 垃圾回收监视


这里有如下demo所需文件 java2demo.jar。
      首先,这里运行

java -Xmx120m -Xms30m -Xmn10m -XX:PermSize=20m -XX:PermSize=20m -XX:+UseSerialGC -jar java2demo.jar 

1). 使用jvisualvm命令

在命令行键入上述代码段,之后输入jvisualvm 命令,然后选择运行demo所在的pid即可监视相关资源使用和GC回收情况。


关于图示分析:

java -Xms30m -Xmx120m -XX:PermSize=20m -XX:MaxPermSize=30m -XX:SurvivorRatio=3 -XX:+UseSerialGC -jar java2demo.jar

这里将参数设置解释一下:

-Xms30m: 设置堆大小起始为30m;

-Xmx120m: 设置堆最大为120m;

-XX:PermSize=20m:设置永久带起始大小为20m;

-XX:MaxPermSize=30m:设置永久带最大值为30m;

-XX:SurvivorRatio=3:设置Eden Generation/Survivor=3;

-XX:+UseSerialGC: 设置垃圾回收策略为简单的串行垃圾回收。



根据截图解释:

  • 老年代和年轻带如果不手动设置-XX:NewRatio=?,则系统取默认值2.这里的Heap大小设置为120m,所以老年代80m, 年轻带40m.
  • 由于设置了-XX:SurvivorRatio=3, 年轻带为40m, 故而Eden Space=40/(3+1+1)*3=24m, Survivor Space =40/(3+1+1)*1=8m.
  • Survivor 0 & Survivor 1 总有一个是空置的。

2). 通过jconsole 命令,这里不在赘述。

3). 使用jstat 命令

MacBook-Pro:~ fqyuan$ ps -eaf | grep java2demo.jar
  501  6431  6097   0 10:03AM ttys000    6:21.67 java -Xms30m -Xmx120m -XX:PermSize=20m -XX:MaxPermSize=30m -XX:SurvivorRatio=3 -XX:+UseSerialGC -jar java2demo.jar
  501  6611  6600   0 10:23AM ttys002    0:00.00 grep java2demo.jar
MacBook-Pro:~ fqyuan$ jstat -gc 6431 1000
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
8192.0 8192.0  0.0    0.0   24576.0   2324.6   81920.0    76028.3   25472.0 24853.2 3456.0 3264.0     50    0.292  449    52.978   53.270
8192.0 8192.0  0.0    0.0   24576.0   1301.9   81920.0    76107.5   25472.0 24853.2 3456.0 3264.0     50    0.292  450    53.163   53.455
8192.0 8192.0  0.0    0.0   24576.0   2831.1   81920.0    76107.5   25472.0 24853.2 3456.0 3264.0     50    0.292  450    53.163   53.455
8192.0 8192.0  0.0    0.0   24576.0   5069.4   81920.0    76107.5   25472.0 24853.2 3456.0 3264.0     50    0.292  450    53.163   53.455
8192.0 8192.0  0.0    0.0   24576.0   8039.7   81920.0    76107.5   25472.0 24853.2 3456.0 3264.0     50    0.292  450    53.163   53.455
8192.0 8192.0  0.0    0.0   24576.0  10764.9   81920.0    76107.5   25472.0 24853.2 3456.0 3264.0     50    0.292  450    53.163   53.455
8192.0 8192.0  0.0    0.0   24576.0  13683.8   81920.0    76107.5   25472.0 24853.2 3456.0 3264.0     50    0.292  450    53.163   53.455
8192.0 8192.0  0.0    0.0   24576.0  15767.2   81920.0    76107.5   25472.0 24853.2 3456.0 3264.0     50    0.292  450    53.163   53.455
8192.0 8192.0  0.0    0.0   24576.0  17675.3   81920.0    76107.5   25472.0 24853.2 3456.0 3264.0     50    0.292  450    53.163   53.455
8192.0 8192.0  0.0    0.0   24576.0   993.8    81920.0    76822.4   25472.0 24864.9 3456.0 3265.6     50    0.292  451    53.372   53.664
8192.0 8192.0  0.0    0.0   24576.0   1028.9   81920.0    72249.2   25472.0 24864.9 3456.0 3265.6     50    0.292  452    53.594   53.886
8192.0 8192.0  0.0    0.0   24576.0   1592.3   81920.0    72267.8   25472.0 24864.9 3456.0 3265.6     50    0.292  453    53.788   54.080
8192.0 8192.0  0.0    0.0   24576.0   1674.7   81920.0    72441.0   25472.0 24864.9 3456.0 3265.6     50    0.292  454    53.969   54.261
8192.0 8192.0  0.0    0.0   24576.0   3588.5   81920.0    72441.0   25472.0 24864.9 3456.0 3265.6     50    0.292  454    53.969   54.261
8192.0 8192.0  0.0    0.0   24576.0   4908.1   81920.0    72441.0   25472.0 24864.9 3456.0 3265.6     50    0.292  455    53.969   54.261
8192.0 8192.0  0.0    0.0   24576.0   377.0    81920.0    72548.1   25472.0 24864.9 3456.0 3265.6     50    0.292  456    54.336   54.628
8192.0 8192.0  0.0    0.0   24576.0   1760.2   81920.0    72548.1   25472.0 24864.9 3456.0 3265.6     50    0.292  456    54.336   54.628
8192.0 8192.0  0.0    0.0   24576.0   3430.4   81920.0    72548.1   25472.0 24864.9 3456.0 3265.6     50    0.292  456    54.336   54.628
8192.0 8192.0  0.0    0.0   24576.0   5381.4   81920.0    72548.1   25472.0 24864.9 3456.0 3265.6     50    0.292  456    54.336   54.628

首先用 ps -eaf| grep java2demo.jar 得到所运行线程的pid(也可用jps 命令);

然后用jstat -gc 6431 1000;6431指代的是线程pid, 1000表示每过1000ms输出一次结果。

S0C:幸存区0的当前大小,以KB为单位。

S1C:幸存区1的当前大小,以KB为单位。

S0U:幸存区0的当前使用内存大小,以 KB为单位。

S1U:幸存区1的当前使用内存大小,以KB为单位。注意,总是有一个幸存区总是空的。
EC:Current Eden Space大小,当前伊甸区大小,以KB为单位。
EU:当前伊甸区使用的大小,以KB为单位。
OC:老年代的大小,以KB为单位。
OU:老年代内存使用情况,以KB为单位。
MC:元数据内存的大小,以KB为单位。
MU:元数据区使用大小,以KB为单位。
CCSC:Compressed class space capacity,当前压缩类空间大小,以KB为单位。
CCSU:压缩类空间使用情况,以KB为单位。
YGC:number of young generation GC events, 年轻带GC发生次数。
YGCT:Young generation collection time, 年轻带GC时间。
FGC:number of full GC events, 完全GC发生的次数。
FGCT:完全GC所用时间。
GCT:GC所用总时间。





你可能感兴趣的:(java,jvm,内存管理,heap,jstat)