1.GC的概念
-Garbage Collection 垃圾收集
垃圾:在系统运行当中,产生的无用的对象。
在c 或者c++里面,就需要程序员去申请,管理内存空间。
这里有一些垃圾回收的线程一直在跑,防止由程序员引入人为的内存泄漏。
-Gc的对象是堆空间和永久区
2.GC算法
1…引用计数法
--老牌的垃圾回收算法
--为每个对象都标记一个适用对象。
即有一个使用了这个对象,就在这个对象下面+1,有一个释放掉了就-1。当引用数量为0时,空间就释放
-- com // ActionScript3 //Python
--存在一个问题,就是对象的多重引用之中,如果去掉了根对象的引用,这个对象仍然有一条1的记录存在,按照道理是不应该被清除的,但是这里的最原始的根的引用已经被取消掉了
那么这个对象的存在就是一个悖论。
2…标记清除法
--现代垃圾回收算法的思想基础。两个阶段,标记阶段,通过根节点,标记所有从根节点开始的可达对象,因此未被标记的对象就时未被引用的垃圾对象。清除阶段,清除所有为标记
对象。
3…标记压缩法
--适用于存活对象较多的场合。比如老年代。他的标记和上面的标记一样,同样是把可以到达的对象标记下来。但在后面不是清理未被标记的对象而是把所有存活的对象压到内存的一端。然后哦
清理边界外,所有的空间。
如图4所示:
4…复制算法
--对于标记清除算法来说,是一种相对高效的算法。
--不适于多生存对象,例如老年代
--原有的内存空间平均分成两块,把一块的存活对象复制到另一块。清除正在使用的内存块中的所有对象,交换内存角色。完成垃圾回收。
--对空间是由浪费的。只能使用一般空间。
因此就与标记整合算法整合到一起。
--但是存在一些大对象,这些对象明显不适合放在复制算法的内存当中。所以一些大对象直接进入担保空间(老年代),因为如果大对象放进复制空间,就会挤的一些小对象放不进去只能进入老年代,这样明显不合理、或者大对象直接放不进去
(老年代中的对象主要有两种来源,要么是存活很多次的对象一直未被清除,这个对象+1,进入老年代,要么是新生代大对象进入老年代)---->标记整合
5…分代思想
--根据存活周期进行分类。短命对象归为新生代,长命对象归为老年代。
会有算法来进行分类。
--少量对象存活,适合复制算法。
--大量对象存活,适合标记清理或者标记清除。
3.可触及性
--可触及的
从根节点开始可以触及到的
--可复活的
有可能会被再次触及
---一旦所有引用被释放,那就是可复活状态
---因为在finalize()中可能复活该对象
--不可触及的
---在finlize()后,可能会进入不可触及状态
---不可触及的对象,把不可能复活
---可以回收
Example:
public class CanReliveObj {
public static CanReliveObj obj;
@Overrideprotected
void finalize() throws Throwable {
super.finalize();
System.out.println("CanReliveObj finalize called");
obj=this;
}
@Overridepublic
String toString(){
return "I am CanReliveObj";
}
public static void main(String[] args) throwsInterruptedException{
obj=new CanReliveObj();
obj=null; //可复活
System.gc();//gc后,obj如果不是存活对象,就直接走else的循环。如果是存活对象,且存储的值是null,就走第一个循环。
Thread.sleep(1000);
if(obj==null){
System.out.println("obj 是 null");}
else{
System.out.println("obj 可用");}
System.out.println("第二次gc");
obj=null; //不可复活
System.gc();
Thread.sleep(1000);
if(obj==null){
System.out.println("obj 是 null");
}
else{
System.out.println("obj 可用");
}
}
解释: 在这个方法当中,给了object = null,上面提到了可复活对象使用的一个方式是使用finlize方法,所以当第一次调用 的时候,obj 可用。当你第二次调用了之后,
finlize就不可用了,obj = null。调用可以使得对象复活,调用之后才有可能使得对象被回收。
但是像这样一个问题,调用了finalize方法,如果第二次我不把obj分配成null,那么是不是这个永远都是一个存活对象?这就是 比较危险的一个操作。
因此:::
---避免使用finalize方法,操作不慎可能会出现一些错误。可以使用try-catch-finally来代替它
---优先级低。因为他是通过gc触发的,而gc什么时候触发,不确定,因此finalize什么时候触发也不确定。
-根
--栈中引用的对象
--方法区中静态成员或者常量引用的对象(全局对象)
--jui方法栈中引用对象
4.Stop-The-World
停止大世界
--Java中 全局停顿的现象,所有的线程
--全局停顿,所有java代码停止执行,native代码可以执行,但不能和jvm交互(这个时候的jvm是一种挂起的状态)
--Stop-The-World引起的多半原因是GC。但是也可能是Dump线程,死锁检查,堆Dump引起的。这个Dump可能是程序员在打印dump的时候,发生的。
-为什么会产生全局停顿?
--类似聚会。如果要打扫垃圾,就必须停止所有活动,不能是一边产生,一边清理。
--危害
---长时间停止服务,没有响应。
---遇到HA系统,可能引起准备切换(当你主机引发了STW时,备用机启用),但是这个主机是要恢复启用的,过一会主机启用了,那么stand-by也在启用,那么数据不一致,严重危害生产环境。
example:
/*
每秒打印10条
*/
public static class PrintThread extends Thread{
public static final long starttime=System.currentTimeMillis();
@Overridepublic void run(){
try {
while(true) {
long t=System.currentTimeMillis()-starttime;
System.out.println("time: "+t) ;
Thread.sleep(100) ;
}
}catch(Exception e){
}
}
}
/*
工作线程,消耗内存
大于450M时,清理内存
-Xmx512M -Xms512M -XX:+UseSerialGC -Xloggc:gc.log
-XX:+PrintGCDetails
-Xmn1m
-XX:PretenureSizeThreshold=50 -XX:MaxTenuringThreshold=1
*/
public static class MyThread extends Thread{
HashMap<Long,byte[]> map = new HashMap<Long,byte[]>( );
@Overridepublic void run(){
try {
while(true) {
if (map.size()*512/1024/1024>= 450) {//512个数组
System.out.println(“=====准备清理===== :"+map.size()) ;
map.clear();
}for (int i =0;i<1024 ;i++) {//每隔一毫秒,就进行一次循环
map.put(System.nanoTime(), new byte[512]);
}
Thread.sleep(1) ;
}
}catch(E xception e){
e.printStackTrace();
}
}
}
结果如下:
time:2018 在这里面每隔0.1s就输出一次
time:2121 在这里面每隔0.1s就输出一次
time:2221 在这里面每隔0.1s就输出一次
time:2325 在这里面每隔0.1s就输出一次
time:2425 在这里面每隔0.1s就输出一次
time:2527 在这里面每隔0.1s就输出一次
time:2631 在这里面每隔0.1s就输出一次
time:2731 在这里面每隔0.1s就输出一次
time:2834 在这里面每隔0.1s就输出一次
time:2935 在这里面每隔0.1s就输出一次
time:3035 在这里面每隔0.1s就输出一次
time:3153 在这里面每隔0.1s就输出一次
time:3504 在这里面每隔0.1s就输出一次
time:4218======before clean map=======:921765
time:4349[error] gc引起停顿了
time:4450[error] gc引起停顿了
time:4551[error] gc引起停顿了
3.292: [GC3.292: [DefNew: 959K->63K(960K), 0.0024260 secs]523578K->523298K(524224K), 0.0024879 secs][Times: user=0.02 sys=0.00, real=0.00 secs]
3.296: [GC3.296: [DefNew: 959K->959K(960K), 0.0000123 secs]3.296: [Tenured: 523235K->523263K(523264K), 0.2820915 secs]524195K->523870K(524224K), [Perm : 147K->147K(12288K)], 0.2821730 secs][Times: user=0.26 sys=0.00, real=0.28 secs]
3.579: [Full GC3.579: [Tenured: 523263K->523263K(523264K), 0.2846036 secs]524159K->524042K(524224K), [Perm : 147K->147K(12288K)], 0.2846745 secs][Times: user=0.28 sys=0.00, real=0.28 secs]
3.863: [Full GC3.863: [Tenured: 523263K->515818K(523264K), 0.4282780 secs]524042K->515818K(524224K), [Perm : 147K->147K(12288K)], 0.4283353 secs][Times: user=0.42 sys=0.00, real=0.43 secs]
4.293: [GC4.293: [DefNew: 896K->64K(960K), 0.0017584 secs]516716K->516554K(524224K), 0.0018346 secs][Times: user=0.00 sys=0.00, real=0.00 secs]
......省略若干.....
4.345: [GC4.345: [DefNew: 960K->960K(960K), 0.0000156 secs]4.345: [Tenured: 522929K->12436K(523264K), 0.0781624 secs]523889K->12436K(524224K), [Perm : 147K->147K(12288K)], 0.0782611 secs][Times: user=0.08 sys=0.00, real=0.08 secs]