20
20
21
21
![ ] ( http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-8-26/29176325.jpg )
22
22
23
- 当需要排查各种 内存溢出问题、当垃圾收集称为系统达到更高并发的瓶颈时 ,我们就需要对这些“自动化”的技术实施必要的监控和调节。
23
+ 当需要排查各种 内存溢出问题、当垃圾收集成为系统达到更高并发的瓶颈时 ,我们就需要对这些“自动化”的技术实施必要的监控和调节。
24
24
25
25
26
26
@@ -32,7 +32,7 @@ Java 的自动内存管理主要是针对对象内存的回收和对象内存的
32
32
33
33
![ ] ( https://user-gold-cdn.xitu.io/2018/8/25/16570344a29c3433?w=599&h=250&f=png&s=8946 )
34
34
35
- 从上图可以看出堆内存的分为新生代 、老年代和永久代。新生代又被进一步分为:Eden 区+Survior1 区+Survior2 区。值得注意的是,在 JDK 1.8中移除整个永久代,取而代之的是一个叫元空间(Metaspace)的区域(永久代使用的是JVM的堆内存空间,而元空间使用的是物理内存,直接受到本机的物理内存限制)。
35
+ 从上图可以看出堆内存分为新生代 、老年代和永久代。新生代又被进一步分为:Eden 区+Survivor1 区+Survivor2 区。值得注意的是,在 JDK 1.8中移除整个永久代,取而代之的是一个叫元空间(Metaspace)的区域(永久代使用的是JVM的堆内存空间,而元空间使用的是物理内存,直接受到本机的物理内存限制)。
36
36
37
37
![ ] ( http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-8-27/89294547.jpg )
38
38
@@ -42,7 +42,7 @@ Java 的自动内存管理主要是针对对象内存的回收和对象内存的
42
42
43
43
大多数情况下,对象在新生代中 eden 区分配。当 eden 区没有足够空间进行分配时,虚拟机将发起一次Minor GC.下面我们来进行实际测试以下。
44
44
45
- 在测试之前我们先来看看 ** Minor Gc和Full GC 有什么不同呢?**
45
+ 在测试之前我们先来看看 ** Minor GC和Full GC 有什么不同呢?**
46
46
47
47
- ** 新生代GC(Minor GC)** :指发生新生代的的垃圾收集动作,Minor GC非常频繁,回收速度一般也比较快。
48
48
- ** 老年代GC(Major GC/Full GC)** :指发生在老年代的GC,出现了Major GC经常会伴随至少一次的Minor GC(并非绝对),Major GC的速度一般会比Minor GC的慢10倍以上。
@@ -76,7 +76,7 @@ allocation2 = new byte[900*1024];
76
76
```
77
77
![ ] ( http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-8-26/28128785.jpg )
78
78
79
- ** 简单解释一下为什么会出现这种情况:** 因为给allocation2分配内存的时候eden区内存几乎已经被分配完了,我们刚刚讲了当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC.GC期间虚拟机又发现allocation1无法存入Survior空间 ,所以只好通过 ** 分配担保机制** 把新生代的对象提前转移到老年代中去,老年代上的空间足够存放allocation1,所以不会出现Full GC。执行Minor GC后,后面分配的对象如果能够存在eden区的话,还是会在eden区分配内存。可以执行如下代码验证:
79
+ ** 简单解释一下为什么会出现这种情况:** 因为给allocation2分配内存的时候eden区内存几乎已经被分配完了,我们刚刚讲了当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC.GC期间虚拟机又发现allocation1无法存入Survivor空间 ,所以只好通过 ** 分配担保机制** 把新生代的对象提前转移到老年代中去,老年代上的空间足够存放allocation1,所以不会出现Full GC。执行Minor GC后,后面分配的对象如果能够存在eden区的话,还是会在eden区分配内存。可以执行如下代码验证:
80
80
81
81
``` java
82
82
public class GCTest {
@@ -102,7 +102,7 @@ public class GCTest {
102
102
为了避免为大对象分配内存时由于分配担保机制带来的复制而降低效率。
103
103
104
104
### 1.3 长期存活的对象将进入老年代
105
- 既然虚拟机采用了分代收集的思想来管理内存,那么内存回收时就必须能识别那些对象应放在新生代,那些对象应放在老年代中 。为了做到这一点,虚拟机给每个对象一个对象年龄(Age)计数器。
105
+ 既然虚拟机采用了分代收集的思想来管理内存,那么内存回收时就必须能识别哪些对象应放在新生代,哪些对象应放在老年代中 。为了做到这一点,虚拟机给每个对象一个对象年龄(Age)计数器。
106
106
107
107
如果对象在 Eden 出生并经过第一次 Minor GC 后仍然能够存活,并且能被 Survivor 容纳的话,将被移动到 Survivor 空间中,并将对象年龄设为1.对象在 Survivor 中每熬过一次 MinorGC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数 ` -XX:MaxTenuringThreshold ` 来设置。
108
108
@@ -163,13 +163,13 @@ JDK1.2以后,Java对引用的概念进行了扩充,将引用分为强引用
163
163
164
164
** 2.软引用(SoftReference)**
165
165
166
- 如果一个对象只具有软引用,那就类似于** 可有可物的生活用品 ** 。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
166
+ 如果一个对象只具有软引用,那就类似于** 可有可无的生活用品 ** 。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
167
167
168
168
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,JAVA虚拟机就会把这个软引用加入到与之关联的引用队列中。
169
169
170
170
** 3.弱引用(WeakReference)**
171
171
172
- 如果一个对象只具有弱引用,那就类似于** 可有可物的生活用品 ** 。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。
172
+ 如果一个对象只具有弱引用,那就类似于** 可有可无的生活用品 ** 。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。
173
173
174
174
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
175
175
@@ -230,15 +230,15 @@ JDK1.2以后,Java对引用的概念进行了扩充,将引用分为强引用
230
230
![ 复制算法] ( http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-8-27/90984624.jpg )
231
231
232
232
### 3.3 标记-整理算法
233
- 根据老年代的特点特出的一种标记算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一段移动 ,然后直接清理掉端边界以外的内存。
233
+ 根据老年代的特点特出的一种标记算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一端移动 ,然后直接清理掉端边界以外的内存。
234
234
235
235
![ 标记-整理算法] ( http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-8-27/94057049.jpg )
236
236
237
237
### 3.4 分代收集算法
238
238
239
239
当前虚拟机的垃圾手机都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
240
240
241
- ** 比如在新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清楚 ”或“标记-整理”算法进行垃圾收集。**
241
+ ** 比如在新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清除 ”或“标记-整理”算法进行垃圾收集。**
242
242
243
243
** 延伸面试问题:** HotSpot为什么要分为新生代和老年代?
244
244
@@ -250,7 +250,7 @@ JDK1.2以后,Java对引用的概念进行了扩充,将引用分为强引用
250
250
251
251
** 如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。**
252
252
253
- 虽然我们对各个收集器进行比较,但并非了挑选出一个最好的收集器 。因为知道现在为止还没有最好的垃圾收集器出现,更加没有万能的垃圾收集器,** 我们能做的就是根据具体应用场景选择适合自己的垃圾收集器** 。试想一下:如果有一种四海之内、任何场景下都适用的完美收集器存在,那么我们的HotSpot虚拟机就不会实现那么多不同的垃圾收集器了。
253
+ 虽然我们对各个收集器进行比较,但并非要挑选出一个最好的收集器 。因为知道现在为止还没有最好的垃圾收集器出现,更加没有万能的垃圾收集器,** 我们能做的就是根据具体应用场景选择适合自己的垃圾收集器** 。试想一下:如果有一种四海之内、任何场景下都适用的完美收集器存在,那么我们的HotSpot虚拟机就不会实现那么多不同的垃圾收集器了。
254
254
255
255
256
256
### 4.1 Serial收集器
0 commit comments