建设外贸商城网站,昆明网站建设方案优化,wordpress字体格式,电子商务网站建设技能实训答案Q什么是垃圾#xff1a; 运行程序中#xff0c;没用任何指针指向的对象。
Q为什么需要垃圾回收#xff1f; 内存只分配#xff0c;不整理回收#xff0c;迟早会被消耗完。
内存碎片的整理#xff0c;为新对象腾出空间
没有GC程序无法正常进行。
Q 哪些区域有GC#…Q什么是垃圾 运行程序中没用任何指针指向的对象。
Q为什么需要垃圾回收 内存只分配不整理回收迟早会被消耗完。
内存碎片的整理为新对象腾出空间
没有GC程序无法正常进行。
Q 哪些区域有GC哪些区域会有OOM异常(错误)
堆和方法区是线程共享的存在GC 和OOM 堆有新生代和养老代默认比例1:2 新生代分为Eden :s0:s1 默认比例 8:1:1 (实际发现JDK8是6:1:1,一度怀疑是自适应策略结果不是) 新生代中有YGC/MinorGC, 当Eden区满的时候触发并使用复制算法和分代策略将Eden区和from区的存活对象 放到to区如果存不下就直接晋升老年代。 其余对象在对象头的分代阈值为15时晋升到老年代。
老年代垃圾回收为MajorGC一般是老年代满的时候会被触发。为全堆回收
方法区若发生GC为FUllGC此时会对全堆以及方法区进行垃圾回收。
简单一句话频繁收集年轻代较少收集老年代基本不动元空间。
PC寄存器 即没用GC 也没用OOM
虚拟机栈无GC有OOM 当栈的大小可以被动态扩容时申请扩容的大小已经超过了内存可以支配空间发生OOM StackOverFlowError当栈空间大小是固定的当前栈帧没有足够空间入栈了此时方式 SOFERROR
Q垃圾回收相关算法
标记阶段引用计数和可达性分析算法。目的判断对象的存活。
引用计数 一个对象A有一个引用计数器。当A被任何一个对象引用了则A的计数器加1。引用失效引用计数器则减1。 PS什么叫A被一个对象引用了举个例子。
class ReferenceClass{ //static filed public static A a new A(); } 对象(new A()),被对象 ReferenceClass的静态变量引用我们知道类变量的初始化是在类加载三部曲的初始化阶段clint里随着类卸载而消亡。 若ReferenceClass类的生命周期不结束。对象(new A())就会一直被类变量a 引用着。 这里再发散静态变量在逻辑上是存放在方法区的从JDK7以后静态变量和字符串常量池就存放在了堆空间中。
引用计数法有个缺陷循环引用问题。 注意java在标记阶段并没有使用引用计数算法。
在分析引用、对象等问题的时候。 一定要注意一个问题这个引用到底是在方法中(局部变量)还是在类内的成员变量上 因为从内存解构上局部引用是在虚拟机栈的局部变量表中的而类内的成员变量引用是在堆内的。
比如 class InstanceA{ //此引用的位置是在对象内存解构中的 Object ref null; public static void main(String[] args){ //这个引用a1是在局部变量表中的 Instance a1 new Instance(); //这个ref 是在堆中对象体内的 a1.ref a1; //操作数栈指向堆内对象的指针断开。a1.ref 是在堆内又指向自己。 a1 null; }
}
Python使用的就是引用计数解决循环引用的两个方法 手动解除引用。 使用弱引用。
可达性分析算法追踪性垃圾收集 首先要搞清楚什么是GC Roots GC roots 是一组集合它包括 1、虚拟机栈中的引用的对象 比如 各个线程中被调用的方法中使用到的参数局部变量等 2、本地方法栈引用的对象。 3、方法区静态属性引用的引用的对象。如上面的例子A是引用类型的静态类型变量它就是一个典型的GC root class ReferenceClass{ //static filed public static A a new A(); }
4、方法区中常量引用对象。 class Demo{ String s abc; public void foo(){ String dddXXXYYY; //局部变量表最大slot深度为2,ddd为局部变量表中变量XXXYYY在常量池中 }
}
5、所有被同步锁持有的对象 同步监视器
6、java虚拟机内部的引用 各种常驻对象比如NUllPointerExceptionOOM还有系统类加载器。基本数据类型的Class对象
关于Class对象的内存模型 7、根据不同的垃圾收集器以及当前回收区域不同也会有一些临时性的GC roots对象加入。 比如使用G1回收器时新生代的region里的对象被老年代的某些对象所引用。此时老年代的引用就是临时的GC Roots 即指向某一堆内存中的对象的引用(指针)其本身与被引用对象不在一个回收的逻辑区内它就是GC roots
为了保证GC roots的准确性就需要在可达性分析时内存是一个快照状态而非运行时。保证其一致性。 此时就会产生STW stop the world。 补问Q 对象的finalization机制
对象终止机制系统进行垃圾回收之前会调用该对象的finalize()方法。 该方法是Object类所有允许被子类所重写。用于在对象回收时进行资源释放清理等操作。
但是注意不要主动去调用某个对象的finalize方法而是交给垃圾回收机制去调用GC的finalizer守护线程。
对象可能有三种状态 可触及的从根节点开始可以到达这个对象 可复活的无引用的对象可以在 finalize()中复活。 不可触及的对象的finalize()被调用但是没用复活此时对象为不可触及状态finalize只能被调用一次
只有对象处于不可触及状态才能被回收。
清除阶段
标记-清除mark-sweep 注意标记的不是垃圾而是非垃圾(可达对象)。 两次遍历 1、标记阶段从根节点依次向下逐一遍历找到所有的引用链。(递归遍历) 2、清除阶段 对堆内存从头至尾线性遍历找到没用标记的对象进行回收。
缺点清理出来的空闲空间不连续在新分配对象时候内存分配采用空闲列表
复制算法 原理和思路就像我们理解的YGC的回收策略Eden from to 来回倒腾。
注意点 复制算法适合存活对象比较少的内存空间如果对象过多复制成本是很大的。 一般用在新生代回收
标记-压缩 mark-compact
在mark-sweep之后进行了一次 压缩整理。 可以理解为mark-sweep-compact
其特点是 对象在发生了移动。 整理后空闲区是规整的新对象进行内存分配时候可以进行指针碰撞不再需要维护一个空闲列表
整体来说复制算法最快但是要移动对象且浪费内存。 标记压缩速度最慢且移动对象但是空间开销很少且没用内存碎片 标记清除速度中等不需要移动对象空间开销小但是会产生一些内存碎片。
分代收集 对不同生命周期的对象采取不同的收集方式提高回收效率。 比如我们现在用的Hotspot虚拟机将对象分为 年轻代 老年代
增量式收集用户线程与GC线程并发执行尽可能减少STW 其实仍是给予标记清除和 复制算法。允许垃圾收集线程以分阶段的方式完成标记、清理或复制。 但是这样频繁进行线程和上下文切换增大系统开销降低系统吞吐量而且并发执行要处理好一致性问题对垃圾与非垃圾要做进一步的修正标记。