一、垃圾
在c或c++中垃圾是要手动进行回收的
Java:new对象申请内存
自动回收内存,若手动释放内存,容易出现两种类型问题:
1、忘记回收,导致内存溢出
2、多次回收
二、什么是垃圾
1、如果一个对象没有任何引用指向他
2、存在多个对象,互相之间引用,没有其他对象指向这个循环引用的对象(多个)
三、如何定位垃圾
1、引用计数法:一个对象有几个引用,这个对象中的计数器为相应的数,当计数器为0时,为垃圾(不能解决循环引用的问题)
但是,当三个对象循环引用,每个对象的计数器都为1,此时没有对象引用该整体时,会发生内存泄漏
2、根可达算法:程序会找到一些根对象,与根对象有关联的都不是垃圾,其余都是垃圾
四、垃圾回收算法
1、标记清除:找到垃圾后清除,相应区域标记为非垃圾区域
存在问题:位置不连续、产生碎片
黑色为垃圾,绿色为未使用
2、拷贝:将内存区域非为两半,在上半区找到正在使用的内存,拷贝到下半区。拷贝完成后将上半区清空,标记为未使用区域,需要内存时往下半区分配
存在问题:浪费空间,需要准备两份。项目中需要5G,你要准备10G内存
3、标记压缩:从头开始按照顺序,将存活对象拷贝到可回收区域,形成连续空间
好处:没有碎片,内存连续。但是效率偏低
效率偏低原因:若单线程操作,效率本身就低
若多线程操作,需要线程同步
五、JVM内存分代模型
1、部分垃圾回收器使用的模型
2、新生代+老年代+永久代(1.7)/元数据区(1.8)
永久代、元数据都是装Class对象中
永久代必须指定大小限制,元数据区可以设置也可以不设置
3、堆内存逻辑分区
新生代=伊甸+2个survivor区
①YGC回收之后,大多数内存会被回收,存活的对象进入S0,伊甸园区清空
②伊甸+S0中存活的对象拷贝到S1中,其余两个区域清空
③再次YGC,伊甸+S1中存活对象放到S0中
④当对象年龄足够大或S区装不下后,放到老年代中
老年代满之后会触发FGC(Full GC)
4、调优目标:尽量减少FGC
默认新生代:老年代=1:3
新生代中伊甸:survivor:survivor = 8:1:1
六、常见的垃圾回收器
Serial(年轻代,串行回收,单线程):从左到右,空间满了,触发GC,所有程序线程停止,垃圾回收线程进行垃圾回收,回收后程序继续运行
蓝色的线表示程序正常运行
Paraller Scavenge(年轻代,并行回收)
ParNew(年轻代):配合CMS的并行回收
SerialOld:将Serial放到old区
ParallelOld:将Parallel放到old区
CMS(老年代):在进行垃圾回收的时候程序也可以运行,效率较高,降低STW的时间(200ms)
G1(10ms)
ZGC(1ms)