程序的栈和堆
栈先进后出,且里面的数据自动释放,
堆内的空间则需要手动释放
java python go
只管创建,不用像c,c++需要手动释放空间,
因为他们都会开一个进程GC(Garbage Collector),由垃圾回收器来复制回收
如何分辨什么是垃圾?如何定位垃圾
Java使用的方法是RootSearching,例如main方法的根开始,往下走,只要能通的空间,就不是垃圾,走不通的且存在的空间都是垃圾
常用的垃圾回收算法和垃圾回收器
三种垃圾回收算法
Mark-Sweep(标记清除)
原来是垃圾的部分,标记可用(清掉垃圾),则该部分就可以等待使用了,但容易碎片化
Copying(拷贝)
就把与根相关的空间存储到另一片区域,然后这部分区域全部清除,但太浪费内存了
Mark-Compact(标记压缩)
把与根相关的空间,按序排好,其余清掉,效率最低
三种算法的综合运用,产生了各式各样的垃圾回收器
GC
前6种垃圾回收期应用堆内存分为两代的情况,后四种堆内存分为多块
随着内存大小的不断增长而演进
GC方式一:堆内存逻辑分区,分代(青年代,老年代)
进程一创建先放入eden,然后进行第一次垃圾清除,如果没有清除,则转入survivor,再一次清除则又放入第二个survivor,两个survivor来回存放和清除且记录次数,当到达某个次数,则可以进入老年代,老年代中的空间不会每次都进行垃圾清除。
新生代大量死去,少量存活,采用赋值算法
老年代存活率高,回收较少,采用MC或MS
垃圾回收器:Serial and Serial Old(GC)(内存只有几兆-几十兆)
STW规则,当要进行垃圾清除时,所有进程停止活动,直到垃圾清除完毕,
且Serial(应用在新生代) 和 Serial Old,采用mark-sweep-compact i(也是垃圾回收器,应用在老年代) 都是单垃圾回收进程
垃圾回收器:Parallel Scavenge and Parallel Old(GC)(并行多线程)(几十兆-上百兆)
Parallel Scavenge在新生代 Parallel Old 在老年代
多个线程同时处理垃圾
jdk1.8默认垃圾回收器,就是这两个,简称ps + po
垃圾回收器:Concurrent (GC)
这种情况 GC线程和业务线程可以同时执行
CMS 、ParNew、G1、ZGC、Shenandoah都熟悉Concurrent;
CMS
CMS工作在老年代,可以与初生代中的Serial和ParNew搭配使用
常常CMS 与 ParNew(工作在年轻的多线程垃圾回收器,是增强的Parallel Scavenge,就是为了配合CMS使用)
三色标记算法
第一轮垃圾扫描,如果当前节点扫描后且孩子节点也扫描,则标记为黑色,如果只扫描了当前节点,没有扫描它的孩子节点,则标记为灰色,如果当前节点没扫描过,则标记为白色。
CMS方案(Incremental Update):黑色节点,下次垃圾回收线程再扫描时,就不会再扫描了,当黑色节点又指向新节点时,需从黑色改为灰色,这样才能扫描到白色新节点。
Epsilon jdk11产生
什么都不做,只是做内存记录,帮助程序员debug用
G1(摈弃年轻代和老年代,改为分区算法)
物理不分为两个大代,分为多个区,但在逻辑上,存储依然是年轻代和老年代,每个小分区所处的逻辑位置不是固定的,当某个小区域满时,则GC扫描该小区域,把不是垃圾复制到另外一个小区域,清除该小区域。
G1方案(SATB),也是三色标记,但与CMS不同,当第一次扫描后,由于白色没扫到,可能会被当成垃圾,所有把灰色与白色之间的引用做一个记录,放入到GC的堆栈,则下次再扫描时,会看看记录表,这样就不会把区域当成垃圾了
整个区域会有一片区域作为RSET,记录有效的引用
ZGC
颜色指针
分页,不分老年代和年轻代,所有分区都一样,快要满的分区则清除