标记-清除
将存活的对象进行标记,然后清理掉未被标记的对象。
不足:
标记-整理
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
复制
将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。
主要不足是只使用了内存的一半。
分代收集策略
JDK1.8采用分代收集策略
$ java -XX:+PrintCommandLineFlags -version
...
UseParallelGC = Parallel Scavenge + Parallel Old
分代收集是根据对象的存活时间把内存分为新生代和老年代,根据个代对象的存活特点,每个代采用不同的垃圾回收算法。新生代采用标记—复制算法,老年代采用标记—整理算法。
import java.util.UUID;
/**
* @author 小怪兽
* @version 1.0
* @since 2022-11-15
*/
public class Jmap {
private byte[] buffer = new byte[500*1024];
private String h = UUID.randomUUID().toString();
public static void main(String[] args) throws Exception {
int n = 100000;
for (int i = 0; i < n; i++) {
Jmap jmap = new Jmap();
Thread.sleep(10);
}
}
}
可以使用如下脚本监控jvm的内存使用情况
pid=`jps | grep Jmap | awk '{print $1}'`
echo PID: $pid
watch -n 2 -d "jmap -heap $pid"
Every 2.0s: jmap -heap 25834 Tue Nov 15 23:31:43 2022
Attaching to process ID 25834, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.202-b08
using thread-local object allocation.
Parallel GC with 13 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 16846422016 (16066.0MB)
NewSize = 351272960 (335.0MB)
MaxNewSize = 5615124480 (5355.0MB)
OldSize = 703594496 (671.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 264241152 (252.0MB)
used = 95229184 (90.817626953125MB)
free = 169011968 (161.182373046875MB)
36.038740854414684% used
From Space:
capacity = 43515904 (41.5MB)
used = 0 (0.0MB)
free = 43515904 (41.5MB)
0.0% used
To Space:
capacity = 43515904 (41.5MB)
used = 0 (0.0MB)
free = 43515904 (41.5MB)
0.0% used
PS Old Generation
capacity = 703594496 (671.0MB)
used = 0 (0.0MB)
free = 703594496 (671.0MB)
0.0% used
1070 interned Strings occupying 78624 bytes.
Heap Usage:
PS Young Generation
Eden Space:
capacity = 264241152 (252.0MB)
used = 206210320 (196.65748596191406MB)
free = 58030832 (55.34251403808594MB)
78.03868490552145% used
From Space:
capacity = 43515904 (41.5MB)
used = 0 (0.0MB)
free = 43515904 (41.5MB)
0.0% used
To Space:
capacity = 43515904 (41.5MB)
used = 0 (0.0MB)
free = 43515904 (41.5MB)
0.0% used
PS Old Generation
capacity = 703594496 (671.0MB)
used = 0 (0.0MB)
free = 703594496 (671.0MB)
0.0% used
1070 interned Strings occupying 78624 bytes.
Heap Usage:
PS Young Generation
Eden Space:
capacity = 264241152 (252.0MB)
used = 264241152 (252.0MB)
free = 0 (0.0MB)
100.0% used
From Space:
capacity = 43515904 (41.5MB)
used = 0 (0.0MB)
free = 43515904 (41.5MB)
0.0% used
To Space:
capacity = 43515904 (41.5MB)
used = 0 (0.0MB)
free = 43515904 (41.5MB)
0.0% used
PS Old Generation
capacity = 703594496 (671.0MB)
used = 0 (0.0MB)
free = 703594496 (671.0MB)
0.0% used
1073 interned Strings occupying 78792 bytes.
Heap Usage:
PS Young Generation
Eden Space:
capacity = 264241152 (252.0MB)
used = 10466912 (9.982025146484375MB)
free = 253774240 (242.01797485351562MB)
3.961121089874752% used
From Space:
capacity = 43515904 (41.5MB)
used = 524320 (0.500030517578125MB)
free = 42991584 (40.999969482421875MB)
1.204892813441265% used
To Space:
capacity = 43515904 (41.5MB)
used = 0 (0.0MB)
free = 43515904 (41.5MB)
0.0% used
PS Old Generation
capacity = 703594496 (671.0MB)
used = 8192 (0.0078125MB)
free = 703586304 (670.9921875MB)
0.0011643070044709389% used
1058 interned Strings occupying 77752 bytes.
Heap Usage:
PS Young Generation
Eden Space:
capacity = 264241152 (252.0MB)
used = 15956744 (15.217536926269531MB)
free = 248284408 (236.78246307373047MB)
6.038705129472036% used
From Space:
capacity = 43515904 (41.5MB)
used = 425984 (0.40625MB)
free = 43089920 (41.09375MB)
0.9789156626506024% used
To Space:
capacity = 43515904 (41.5MB)
used = 0 (0.0MB)
free = 43515904 (41.5MB)
0.0% used
PS Old Generation
capacity = 703594496 (671.0MB)
used = 8192 (0.0078125MB)
free = 703586304 (670.9921875MB)
0.0011643070044709389% used
1058 interned Strings occupying 77752 bytes.
Heap Usage:
PS Young Generation
Eden Space:
capacity = 257949696 (246.0MB)
used = 20690464 (19.731964111328125MB)
free = 237259232 (226.26803588867188MB)
8.021123622491107% used
From Space:
capacity = 524288 (0.5MB)
used = 442384 (0.4218902587890625MB)
free = 81904 (0.0781097412109375MB)
84.3780517578125% used
To Space:
capacity = 1048576 (1.0MB)
used = 0 (0.0MB)
free = 1048576 (1.0MB)
0.0% used
PS Old Generation
capacity = 703594496 (671.0MB)
used = 16384 (0.015625MB)
free = 703578112 (670.984375MB)
0.0023286140089418777% used
1058 interned Strings occupying 77752 bytes.
Heap Usage:
PS Young Generation
Eden Space:
capacity = 257949696 (246.0MB)
used = 58366424 (55.662559509277344MB)
free = 199583272 (190.33744049072266MB)
22.62705671108835% used
From Space:
capacity = 43515904 (41.5MB)
used = 442384 (0.4218902587890625MB)
free = 43073520 (41.07810974121094MB)
1.0166030332266567% used
To Space:
capacity = 524288 (0.5MB)
used = 0 (0.0MB)
free = 524288 (0.5MB)
0.0% used
PS Old Generation
capacity = 703594496 (671.0MB)
used = 24576 (0.0234375MB)
free = 703569920 (670.9765625MB)
0.003492921013412817% used
可以看出,创建新对象是总是在Eden
区操作,随着不断new
对象,Eden
区内存使用不断上升,当Eden
区空间使用达100%
时会执行复制算法将对象复制到From
区, 虽然From
区的容量远小于Eden
区但仍然使Eden的内存使用降到了0%
,这是因为当Eden区满了之后会触发YoungGC(Minor GC)
清理掉垃圾对象。
当再次触发YoungGC(Minor GC)
并且From
区满了之后会将存活对象复制到To
区,就这样循环往复一定次数(默认15次)之后,存活的数据会复制到老年代(Old Generation
)
当老年代的内存不足时会触发Old GC(Major GC)
从概念上讲Old GC(Major GC)指的是针对老年代的GC,Full GC指的是对整个堆空间的GC,不过也有说法是Major GC其实等价于Full GC,因为Major GC其实就是老年代空间不足,新生代的对象没法转移到老年代所以需要先对老年代GC,然后再对新生代GC,可以说Major GC的目的就是为了Minor GC,这其实就是Full GC了。
这里老年代空间不足指的探讨,不足指的是老年代空间使用100%还是超过了一定阈值?这个笔者尚没有看到相关定论,后续可以再深究。