zoukankan      html  css  js  c++  java
  • 垃圾回收算法

    垃圾回收算法
    GC Root:
    1.可达性分析算法
    2.引用计数法
    引用计数器:当对于对象存在引用时,会给这个对象的计数上+1,当引用结束后,会对这个计数减1,当对象的引用计数为0时,代表这个对象可以被回收
    可达性分析算法从一系列GCRoot对象开始,向下搜索引用链,如果一个对象没有与任何GCRoot对象关联,这个对象就会被判定为可回收对象。
    GCRoot包括以下对象:
    1. 虚拟机栈上的本地变量表引用的对象
    2. 方法区中类的静态属性引用的对象
    3. 方法区中常量引用的对象
    4. 本地方法栈中JNI引用的对象
    这一过程称为根节点枚举,也就是垃圾回收中的标记过程,当前所有的垃圾收集器,在标记阶段都必须停止所有java执行线程(stop the world),以保证对象引用状态不会发生变化。
    垃圾收集:是Java提供的一个系统级线程。来跟踪每一块分配出去的内存空间,当Java虚拟机处于空闲循环时,垃圾收集器线程会自动检查每一块分配出去的内存空间,然后自动回收每一块可以回收的无用的内存块。
    是Java提供的一个系统级线程。来跟踪每一块分配出去的内存空间,当Java虚拟机处于空闲循环时,垃圾收集器线程会自动检查每一块分配出去的内存空间,然后自动回收每一块可以回收的无用的内存块。是低优先级的线程,在一个Java程序的生命周期中,它只有在内存空间的时候才有机会运行。它有效防止了内存泄露体的出现,并极大可能地节省了宝贵的内存资源。
    1. 标记 - 清除算法 
    标记清除算法是最基础的收集算法,其他收集算法都是基于这种思想。标记清除算法分为“标记”和“清除”两个阶段:首先标记出需要回收的对象,标记完成之后统一清除对象。
    它的主要缺点:①.标记和清除过程效率不高 。
    ②.标记清除之后会产生大量不连续的内存碎片。
    2. 复制算法
    它将可用内存容量划分为大小相等的两块,每次只使用其中的一块。当这一块用完之后,就将还存活的对象复制到另外一块上面,然后在把已使用过的内存空间一次理掉。这样使得每次都是对其中的一块进行内存回收,不会产生碎片等情况,只要移动堆订的指针,按顺序分配内存即可,实现简单,运行高效。
    主要缺点:内存缩小为原来的一半。
    3. 标记  - 整理算法
    标记操作和“标记-清除”算法一致,后续操作不只是直接清理对象,而是在清理无用对象完成后让所有存活的对象都向一端移动,并更新引用其对象的指针。
    主要缺点:在标记-清除的基础上还需进行对象的移动,成本相对较高,好处则是不会产生内存碎片。
    4、分代收集算法
    根据对象的存活周期的不同将内存划分为几块。一般把java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对他进行分配担保,就必须使用“标记-整理”算法进行回收。
    5、火车算法
          火车算法也称列车算法,是一种更彻底的分区域处理收集算法,是对分代收集算法的一个有力补充
    1、算法思路
          在火车算法中,内存被分为块,多个块组成一个集合。为了形象化,一节车厢代表一个块,一列火车代表一个集合,如下图;
          火车与车箱都按创建顺序标号,每个车厢大小相等,但每个火车包含的车厢数不一定相等;
          每节车箱有一个被记忆集合,而每辆火车的记忆集合是它所有车厢记忆集合的总和;
          记忆集合由指向车箱中对象的引用组成,这些引用来自同一辆火车中序号较高的车箱中的对象,以及序号较高中的对象;
          垃圾收集以车厢为单位,整体算法流程如下
    (1)、选择标号最小的火车;
    (2)、如果火车的记忆集合是空的, 释放整列火车并终止, 否则进行第三步操作;
    (3)、选择火车中标号最小的车厢;
    (4)、对于车厢记忆集合的每个元素:
          如果它是一个被根引用引用的对象, 那么, 将拷贝到一列新的火车中去;
          如果是一个被其它火车的对象指向的对象, 那么, 将它拷贝到这个指向它的火车中去.;
          假设有一些对象已经被保留下来了, 那么通过这些对象可以触及到的对象将会被拷贝到同一列火车中去;
          如果一个对象被来自多个火车的对象引用, 那么它可以被拷贝到任意一个火车去;
          这个步骤中, 有必要对受影响的引用集合进行相应地更新;
    (5)、释放车厢并且终止;
          收集过程会删除一些空车箱和空车,当需要的时候也会创建一些车箱和火车,更多信息请参考:《编译原理》第二版7.75"列车算法"、《渐进式地垃圾回收: 火车算法》
          执行过程如下图:
    2、优点
          可以在成熟对象空间提供限定时间的渐近收集;
          而不需要每次都进行一个大区域的垃圾回收过程;
          即可以控制垃圾回收的时间,在指定时间内进行一些小区域的回收;
    3、缺点
          实现较为复杂,如采用类似的算法的G1收集器在JDK7才实现;
          一些场景下可能性价比不高;
    4、应用场景
          JDK7后HotSpot虚拟机G1收集器采用类似的算法,能建立可预测的停顿时间模型;
    java基础
    1、Static Nested Class 和 Inner Class的不同。 
    Static Nested Class是被声明为静态(static)的内部类,它可以不依赖于外部类实例被实例化。而通常的内部类需要在外部类实例化后才能实例化。
    2、JSP中动态INCLUDE与静态INCLUDE的区别?
    动态INCLUDE用jsp:include动作实现 <jsp:include page="included.jsp" flush="true" />它总是会检查所含文件中的变化,适合用于包含动态页面,并且可以带参数。
    静态INCLUDE用include伪码实现,定不会检查所含文件的变化,适用于包含静态页面<%@ include file="included.htm" %> 
    3、什么时候用assert。 
    assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。一般来说,assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能,在软件发布后,assertion检查通常是关闭的。
    4、GC是什么? 为什么要有GC? 
      GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。 
    5、short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错? 
    short s1 = 1; s1 = s1 + 1; (s1+1运算结果是int型,需要强制转换类型)
    short s1 = 1; s1 += 1;(可以正确编译)
    6、Math.round(11.5)等於多少? Math.round(-11.5)等於多少? 
    Math.round(11.5)==12
    Math.round(-11.5)==-11
    round方法返回与参数最接近的长整数,参数加1/2后求其floor.
    7、String s = new String("xyz");创建了几个String Object? 
    两个
    8、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。
    以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题。
    public class ThreadTest1{
    private int j;
    public static void main(String args[]){
    ThreadTest1 tt=new ThreadTest1();
    Inc inc=tt.new Inc();
    Dec dec=tt.new Dec();
    for(int i=0;i<2;i++){
    Thread t=new Thread(inc);
    t.start();
    t=new Thread(dec);
    t.start();
    }
    }
    private synchronized void inc(){
    j++;
    System.out.println(Thread.currentThread().getName()+"-inc:"+j);
    }
    private synchronized void dec(){
    j--;
    System.out.println(Thread.currentThread().getName()+"-dec:"+j);
    }
    class Inc implements Runnable{
    public void run(){
    for(int i=0;i<100;i++){
    inc();
    }
    }
    }
    class Dec implements Runnable{
    public void run(){
    for(int i=0;i<100;i++){
    dec();
    }
    }
    }
    }
    9、Java有没有goto?
    java中的保留字,现在没有在java中使用。
    10、启动一个线程是用run()还是start()?
    启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。
  • 相关阅读:
    关于表格单元格溢出情况的处理(单行文本溢出或多行文本溢出)
    下拉树的公共插件(手写插件的方法)
    ztree树样式的设计
    Android学习笔记之Intent(2)
    Android学习笔记之Intent(1)
    Ajax
    Android学习笔记之ContentProvider
    Android学习笔记之Broadcast Receiver
    Android学习笔记之Service
    Android学习笔记之Intent
  • 原文地址:https://www.cnblogs.com/llaq/p/9458600.html
Copyright © 2011-2022 走看看