当前位置: 首页 > news >正文

国外优秀摄影作品网站规划网站的总结

国外优秀摄影作品网站,规划网站的总结,互联网 服务平台到哪家好,电子商务网站开发 微盘下载J垃圾回收 1 概述2 方法区的回收3 如何判断对象可以回收3.1 引用计数法3.2 可达性分析法 4 常见的引用对象4.1 软引用4.2 弱引用4.3 虚引用4.4 终结器引用 5 垃圾回收算法5.1 垃圾回收算法的历史和分类5.2 垃圾回收算法的评价标准5.3 标记清除算法5.4 复制算法5.5 标记整理算法… J垃圾回收 1 概述2 方法区的回收3 如何判断对象可以回收3.1 引用计数法3.2 可达性分析法 4 常见的引用对象4.1 软引用4.2 弱引用4.3 虚引用4.4 终结器引用 5 垃圾回收算法5.1 垃圾回收算法的历史和分类5.2 垃圾回收算法的评价标准5.3 标记清除算法5.4 复制算法5.5 标记整理算法5.6 分代垃圾回收算法 1 概述 在C/C这类没有自动垃圾回收机制的语言中一个对象如果不再使用需要手动释放否则就会出现内存泄漏。 内存泄漏指的是不再使用的对象在系统中未被回收内存泄漏的积累可能会导致内存溢出。 为了让程序员更专注于代码的实现而不用过多的考虑内存释放的问题所以在Java语言中有了自动的垃圾回收机制也就是我们熟悉的GC(Garbage Collection)。 有了垃圾回收机制后程序员只需要关心内存的申请即可内存的释放由系统自动识别完成垃圾回收器主要负责对堆上的内存进行回收。 在进行垃圾回收时不同的对象引用类型GC会采用不同的回收时机 换句话说自动的垃圾回收的算法就会变得非常重要了如果因为算法的不合理导致内存资源一直没有释放同样也可能会导致内存溢出的。 当然除了Java语言C#、Python等语言也都有自动的垃圾回收机制。 垃圾回收器如果发现某个对象不再使用就可以回收该对象。 自动垃圾回收自动根据对象是否使用由虚拟机来回收对象 优点降低程序员实现难度、降低对象回收bug的可能性缺点程序员无法控制内存回收的及时性 手动垃圾回收由程序员编程实现对象的删除 优点回收及时性高由程序员把控回收的时机缺点编写不当容易出现悬空指针、重复释放、内存泄漏等问题 那么垃圾回收器需要负责对哪些部分的内存进行回收呢 首先是线程不共享的部分都是伴随着线程的创建而创建线程的销毁而销毁。而方法的栈帧在执行完方法之后就会自动弹出栈并释放掉对应的内存。所以这一部分不需要垃圾回收器负责回收。 2 方法区的回收 方法区中能回收的内容主要就是不再使用的类。 判定一个类可以被卸载。需要同时满足下面三个条件 此类所有实例对象都已经被回收在堆中不存在任何该类的实例对象以及子类对象。 这段代码中就将局部变量对堆上实例对象的引用去除了所以对象就可以被回收。 加载该类的类加载器已经被回收。 这段代码让局部变量对类加载器的引用去除类加载器就可以回收。 该类对应的 java.lang.Class 对象没有在任何地方被引用。 代码 package chapter04.gc;import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList;/*** 类的卸载*/ public class ClassUnload {public static void main(String[] args) throws InterruptedException {try {ArrayListClass? classes new ArrayList();ArrayListURLClassLoader loaders new ArrayList();ArrayListObject objs new ArrayList();while (true) {URLClassLoader loader new URLClassLoader(new URL[]{new URL(file:D:\\lib\\)});Class? clazz loader.loadClass(ClassLoader.A);Object o clazz.newInstance();// objs.add(o); // classes.add(clazz); // loaders.add(loader);System.gc();}} catch (Exception e) {e.printStackTrace();}} }添加这两个虚拟机参数进行测试 -XX:TraceClassLoading -XX:TraceClassUnloading如果注释掉代码中三句add调用就可以同时满足3个条件。但是需要手动调用System.gc()方法让垃圾回收器进行回收。 如果需要手动触发垃圾回收可以调用System.gc()方法。 语法 System.gc() 注意事项 调用System.gc()方法并不一定会立即回收垃圾仅仅是向Java虚拟机发送一个垃圾回收的请求具体是否需要执行垃圾回收Java虚拟机会自行判断。 执行之后日志中就会打印出类卸载的内容 那么类卸载主要用在什么场景下呢 开发中此类场景一般很少出现主要在如 OSGi、JSP 的热部署等应用场景中。 每个jsp文件对应一个唯一的类加载器当一个jsp文件修改了就直接卸载这个jsp类加载器。重新创建类加载器重新加载jsp文件。 3 如何判断对象可以回收 对象的回收发生在堆中 垃圾回收器要回收对象的第一步就是判断哪些对象可以回收。Java中的对象是否能被回收是根据对象是否被引用来决定的。如果对象被引用了说明该对象还在使用不允许被回收。 比如下面代码的内存结构图 第一行代码执行之后堆上创建了Demo类的实例对象同时栈上保存局部变量引用堆上的对象。 第二行代码执行之后局部变量对堆上的对象引用去掉那么堆上的对象就可以被回收了。 一个更复杂的案例 这个案例中如果要让对象a和b回收必须将局部变量到堆上的引用去除。 那么问题来了A和B互相之间的引用需要去除吗答案是不需要因为局部变量都没引用这两个对象了在代码中已经无法访问这两个对象即便他们之间互相有引用关系也不影响对象的回收。 简单一句就是如果一个或多个对象没有任何的引用指向它了那么这个对象现在就是垃圾如果定位了垃圾则有可能会被垃圾回收器回收。 判断对象是否可以回收主要有两种方式引用计数法和可达性分析法。 3.1 引用计数法 引用计数法会为每个对象维护一个引用计数器当对象被引用时加1取消引用时减1。 比如下图中对象A的计数器初始为0局部变量a1对它引用之后计数器加1就变成了1。同样A对B产生了引用B的计数器也是1。 引用计数法的优点是实现简单C中的智能指针就采用了引用计数法但是它也存在缺点主要有两点 每次引用和取消引用都需要维护计数器对系统性能会有一定的影响存在循环引用问题所谓循环引用就是当A引用BB同时引用A时会出现对象无法回收的问题。 这张图上由于A和B之间存在互相引用所以计数器都为1两个对象都不能被回收。但是由于没有局部变量对这两个代码产生引用代码中已经无法访问到这两个对象理应可以被回收。 我们来做一个实验验证下Java中循环引用不会导致内存泄漏因为Java虚拟机根本没有使用引用计数法。首先我们要学会去看一个对象有没有被回收可以通过垃圾回收日志来查看。 如果想要查看垃圾回收的信息可以使用-verbose:gc参数。 语法 -verbose:gc 加上这个参数之后执行代码发现对象确实被回收了 通过不同的死循环创建对象内存并没有上升一直维持在1000K,说明每轮循环创建的两个对象在垃圾回收之后都被回收了。 总结 优点 实时性较高无需等到内存不够的时候才开始回收运行时根据对象的计数器是否为0就可以直接回收。在垃圾回收过程中应用无需挂起。如果申请内存时内存不足则立刻报OOM错误。区域性更新对象的计数器时只是影响到该对象不会扫描全部对象。 缺点 每次对象被引用时都需要去更新计数器有一点时间开销。浪费CPU资源即使内存够用仍然在运行时进行计数器的统计。无法解决循环引用问题会引发内存泄露。最大的缺点 3.2 可达性分析法 Java使用的是可达性分析算法来判断对象是否可以被回收。可达性分析将对象分为两类垃圾回收的根对象GC Root 和普通对象对象与对象之间存在引用关系。 会存在一个根节点【GC Roots】引出它下面指向的下一个节点再以下一个节点节点开始找出它下面的节点依次往下类推。直到所有的节点全部遍历完毕可达性分析算法指的是如果从某个到GC Root对象是可达的对象就不可被回收。 哪些对象被称之为GC Root对象呢 根对象是那些肯定不能当做垃圾回收的对象就可以当做根对象 线程Thread对象引用线程栈帧中的方法参数、局部变量等。 /** * demo是栈帧中的本地变量当 demo null 时由于此时 demo 充当了 GC Root 的作用demo与原来指向的实例 new Demo() 断开了连接对象被回收。*/ public class Demo {public static void main(String[] args) {Demo demo new Demo();demo null;} }系统类加载器加载的java.lang.Class对象引用类中的静态变量。 监视器对象用来保存同步锁synchronized关键字持有的对象。 方法区中类静态属性引用的对象 /*** 当栈帧中的本地变量 b null 时由于 b 原来指向的对象与 GC Root (变量 b) 断开了连接所以 b 原来指向的对象会被回收而由于我们给 a 赋值了变量的引用a在此时是类静态属性引用充当了 GC Root 的作用它指向的对象依然存活!*/ public class Demo {public static Demo a;public static void main(String[] args) {Demo b new Demo();b.a new Demo();b null;} }方法区中常量引用的对象 /** * 常量 a 指向的对象并不会因为 demo 指向的对象被回收而回收*/ public class Demo {public static final Demo a new Demo();public static void main(String[] args) {Demo demo new Demo();demo null;} }本地方法调用时使用的全局对象。 通过arthas和eclipse Memory Analyzer (MAT) 工具可以查看GC RootMAT工具是eclipse推出的Java堆内存检测工具。 4 常见的引用对象 可达性算法中描述的对象引用一般指的是强引用即是GCRoot对象对普通对象有引用关系只要这层关系存在普通对象就不会被回收。除了强引用之外Java中还设计了几种其他引用方式 软引用弱引用虚引用终结器引用 4.1 软引用 软引用相对于强引用是一种比较弱的引用关系如果一个对象只有软引用关联到它当程序内存不足时就会将软引用中的数据进行回收。在JDK 1.2版之后提供了SoftReference类来实现软引用软引用常用于缓存中。 如下图中对象A被GC Root对象强引用了同时我们创建了一个软引用SoftReference对象它本身也是一个对象软引用对象中引用了对象A。 接下来强引用被去掉之后对象A暂时还是处于不可回收状态因为有软引用存在并且内存还够用。 如果内存出现不够用的情况对象A就处于可回收状态可以被垃圾回收器回收。 这样做有什么好处如果对象A是一个缓存平时会保存在内存中如果想访问数据可以快速访问。但是如果内存不够用了我们就可以将这部分缓存清理掉释放内存。即便缓存没了也可以从数据库等地方获取数据不会影响到业务正常运行这样可以减少内存溢出产生的可能性。 特别注意 软引用对象本身也需要被强引用否则软引用对象也会被回收掉。 软引用的执行过程如下 将对象使用软引用包装起来new SoftReference对象类型(对象)。内存不足时虚拟机尝试进行垃圾回收。如果垃圾回收仍不能解决内存不足的问题回收软引用中的对象。如果依然内存不足抛出OutOfMemory异常。 代码 /*** 软引用案例2 - 基本使用*/ public class SoftReferenceDemo2 {public static void main(String[] args) throws IOException {byte[] bytes new byte[1024 * 1024 * 100];SoftReferencebyte[] softReference new SoftReferencebyte[](bytes);bytes null;System.out.println(softReference.get());byte[] bytes2 new byte[1024 * 1024 * 100];System.out.println(softReference.get()); // // byte[] bytes3 new byte[1024 * 1024 * 100]; // softReference null; // System.gc(); // // System.in.read();} }添加虚拟机参数限制最大堆内存大小为200m 执行后发现第二个100m对象创建之后需软引用中包含的对象已经被回收了。 软引用对象本身怎么回收呢 如果软引用对象里边包含的数据已经被回收了那么软引用对象本身其实也可以被回收了。 SoftReference提供了一套队列机制 软引用创建时通过构造器传入引用队列 在软引用中包含的对象被回收时该软引用对象会被放入引用队列 通过代码遍历引用队列将SoftReference的强引用删除 代码 /*** 软引用案例3 - 引用队列使用*/ public class SoftReferenceDemo3 {public static void main(String[] args) throws IOException {ArrayListSoftReference softReferences new ArrayList();ReferenceQueuebyte[] queues new ReferenceQueuebyte[]();for (int i 0; i 10; i) {byte[] bytes new byte[1024 * 1024 * 100];SoftReference studentRef new SoftReferencebyte[](bytes,queues);softReferences.add(studentRef);}SoftReferencebyte[] ref null;int count 0;while ((ref (SoftReferencebyte[]) queues.poll()) ! null) {count;}System.out.println(count);} }最终展示的结果是 这9个软引用对象中包含的数据已经被回收掉所以可以手动从ArrayList中去掉这样就可以释放这9个对象。 软引用的缓存案例 使用软引用实现学生信息的缓存能支持内存不足时清理缓存。 代码 package chapter04.soft;import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.Map; /*** 软引用案例4 - 学生信息的缓存*/ public class StudentCache {private static StudentCache cache new StudentCache();public static void main(String[] args) {for (int i 0; ; i) {StudentCache.getInstance().cacheStudent(new Student(i, String.valueOf(i)));}}private MapInteger, StudentRef StudentRefs;// 用于Cache内容的存储private ReferenceQueueStudent q;// 垃圾Reference的队列// 继承SoftReference使得每一个实例都具有可识别的标识。// 并且该标识与其在HashMap内的key相同。private class StudentRef extends SoftReferenceStudent {private Integer _key null;public StudentRef(Student em, ReferenceQueueStudent q) {super(em, q);_key em.getId();}}// 构建一个缓存器实例private StudentCache() {StudentRefs new HashMapInteger, StudentRef();q new ReferenceQueueStudent();}// 取得缓存器实例public static StudentCache getInstance() {return cache;}// 以软引用的方式对一个Student对象的实例进行引用并保存该引用private void cacheStudent(Student em) {cleanCache();// 清除垃圾引用StudentRef ref new StudentRef(em, q);StudentRefs.put(em.getId(), ref);System.out.println(StudentRefs.size());}// 依据所指定的ID号重新获取相应Student对象的实例public Student getStudent(Integer id) {Student em null; // 缓存中是否有该Student实例的软引用如果有从软引用中取得。if (StudentRefs.containsKey(id)) {StudentRef ref StudentRefs.get(id);em ref.get();} // 如果没有软引用或者从软引用中得到的实例是null重新构建一个实例 // 并保存对这个新建实例的软引用if (em null) {em new Student(id, String.valueOf(id));System.out.println(Retrieve From StudentInfoCenter. ID id);this.cacheStudent(em);}return em;}// 清除那些所软引用的Student对象已经被回收的StudentRef对象private void cleanCache() {StudentRef ref null;while ((ref (StudentRef) q.poll()) ! null) {StudentRefs.remove(ref._key);}}// // 清除Cache内的全部内容 // public void clearCache() { // cleanCache(); // StudentRefs.clear(); // //System.gc(); // //System.runFinalization(); // } }class Student {int id;String name;public Student(int id, String name) {this.id id;this.name name;}public int getId() {return id;}public void setId(int id) {this.id id;}public String getName() {return name;}public void setName(String name) {this.name name;} }4.2 弱引用 弱引用的整体机制和软引用基本一致区别在于弱引用包含的对象在垃圾回收时不管内存够不够都会直接被回收。 在JDK 1.2版之后提供了WeakReference类来实现弱引用弱引用主要在ThreadLocal中使用。 弱引用对象本身也可以使用引用队列进行回收。 package chapter04.weak;import java.io.IOException; import java.lang.ref.WeakReference;/*** 弱引用案例 - 基本使用*/ public class WeakReferenceDemo2 {public static void main(String[] args) throws IOException {byte[] bytes new byte[1024 * 1024 * 100];WeakReferencebyte[] weakReference new WeakReferencebyte[](bytes);bytes null;System.out.println(weakReference.get());System.gc();System.out.println(weakReference.get());} }执行之后发现gc执行之后对象已经被回收了。 延伸话题ThreadLocal内存泄漏问题 ThreadLocal用的就是弱引用看以下源码 static class Entry extends WeakReferenceThreadLocal? {Object value;Entry(ThreadLocal? k, Object v) {super(k);value v; //强引用不会被回收} }Entry的key是当前ThreadLocalvalue值是我们要设置的数据。 WeakReference表示的是弱引用当JVM进行GC时一旦发现了只具有弱引用的对象不管当前内存空间是否足够都会回收它的内存。但是value是强引用它不会被回收掉。 ThreadLocal使用建议使用完毕后注意调用清理方法。 4.3 虚引用 虚引用和终结器引用这两种引用在常规开发中是不会使用的。 虚引用也叫幽灵引用/幻影引用不能通过虚引用对象获取到包含的对象。虚引用唯一的用途是当对象被垃圾回收器回收时可以接收到对应的通知。 Java中使用PhantomReference实现了虚引用直接内存中为了及时知道直接内存对象不再使用从而回收内存使用了虚引用来实现。 必须配合引用队列使用被引用对象回收时会将虚引用入队由 Reference Handler 线程调用虚引用相关方法释放直接内存 4.4 终结器引用 终结器引用指的是在对象需要被回收时终结器引用会关联对象并放置在Finalizer类中的引用队列中在稍后由一条由FinalizerThread线程从队列中获取对象然后执行对象的finalize方法在对象第二次被回收时该对象才真正的被回收。在这个过程中可以在finalize方法中再将自身对象使用强引用关联上但是不建议这样做。 package chapter04.finalreference;/*** 终结器引用案例*/ public class FinalizeReferenceDemo {public static FinalizeReferenceDemo reference null;public void alive() {System.out.println(当前对象还存活);}Overrideprotected void finalize() throws Throwable {try{System.out.println(finalize()执行了...);//设置强引用自救reference this;}finally {super.finalize();}}public static void main(String[] args) throws Throwable {reference new FinalizeReferenceDemo();test();test();}private static void test() throws InterruptedException {reference null;//回收对象System.gc();//执行finalize方法的优先级比较低休眠500ms等待一下Thread.sleep(500);if (reference ! null) {reference.alive();} else {System.out.println(对象已被回收);}} }当对象被标记为可回收后当发生GC时首先会判断这个对象是否执行了finalize方法如果这个方法还没有被执行的话那么就会先来执行这个方法接着在这个方法执行中可以设置当前这个对象与GC ROOTS产生关联那么这个方法执行完成之后GC会再次判断对象是否可达如果仍然不可达则会进行回收如果可达了则不会进行回收。 finalize方法对于每一个对象来说只会执行一次。如果第一次执行这个方法的时候设置了当前对象与RC ROOTS关联那么这一次不会进行回收。 那么等到这个对象第二次被标记为可回收时那么该对象的finalize方法就不会再次执行了。 5 垃圾回收算法 Java是如何实现垃圾回收的呢简单来说垃圾回收要做的有两件事 找到内存中存活的对象。释放不再存活对象的内存使得程序能再次利用这部分空间。 5.1 垃圾回收算法的历史和分类 1960年John McCarthy发布了第一个GC算法标记-清除算法。 1963年Marvin L. Minsky 发布了复制算法。 本质上后续所有的垃圾回收算法都是在上述两种算法的基础上优化而来。 5.2 垃圾回收算法的评价标准 Java垃圾回收过程会通过单独的GC线程来完成但是不管使用哪一种GC算法都会有部分阶段需要停止所有的用户线程。这个过程被称之为Stop The World简称STW如果STW时间过长则会影响用户的使用。 如下图用户代码执行和垃圾回收执行让用户线程停止执行STW是交替执行的。 所以判断GC算法是否优秀可以从三个方面来考虑 1.吞吐量 吞吐量指的是 CPU 用于执行用户代码的时间与 CPU 总执行时间的比值即吞吐量 执行用户代码时间 /执行用户代码时间 GC时间。吞吐量数值越高垃圾回收的效率就越高。 2.最大暂停时间 最大暂停时间指的是所有在垃圾回收过程中的STW时间最大值。比如如下的图中黄色部分的STW就是最大暂停时间显而易见上面的图比下面的图拥有更少的最大暂停时间。最大暂停时间越短用户使用系统时受到的影响就越短。 3.堆使用效率 不同垃圾回收算法对堆内存的使用方式是不同的。比如标记清除算法可以使用完整的堆内存。而复制算法会将堆内存一分为二每次只能使用一半内存。从堆使用效率上来说标记清除算法要优于复制算法。 上述三种评价标准堆使用效率、吞吐量以及最大暂停时间不可兼得。 一般来说堆内存越大最大暂停时间就越长。想要减少最大暂停时间就会降低吞吐量。 没有一个垃圾回收算法能兼顾上述三点评价标准所以不同的垃圾回收算法它的侧重点是不同的适用于不同的应用场景。 5.3 标记清除算法 标记清除算法的核心思想分为两个阶段 根据可达性分析算法得出的垃圾进行标记 对这些标记为可回收的内容进行垃圾回收 可以看到标记清除算法解决了引用计数算法中的循环引用的问题没有从root节点引用的对象都会被回收。 优点 实现简单只需要在第一阶段给每个对象维护标志位第二阶段删除对象即可。 缺点 1.碎片化问题 由于内存是连续的所以在对象被删除之后内存中会出现很多细小的可用内存单元。如果我们需要的是一个比较大的空间很有可能这些内存单元的大小过小无法进行分配。 如下图红色部分已经被清理掉了总共回收了9个字节但是每个都是一个小碎片无法为5个字节的对象分配空间。 2.分配速度慢。 由于内存碎片的存在需要维护一个空闲链表极有可能发生每次需要遍历到链表的最后才能获得合适的内存空间。 我们需要用一个链表来维护哪些空间可以分配对象很有可能需要遍历这个链表到最后才能发现这块空间足够我们去创建一个对象。如下图遍历到最后才发现有足够的空间分配3个字节的对象了。如果链表很长遍历也会花费较长的时间。 3.效率较低标记和清除两个动作都需要遍历所有的对象并且在GC时需要停止应用程序对于交互性要求比较高的应用而言这个体验是非常差的。 5.4 复制算法 复制算法的核心就是将原有的内存空间一分为二From空间和To空间每次只能使用其中的一块空间From空间在垃圾回收时将正在使用的对象复制到另一个内存空间中To空间然后将该内存空间From空间清空交换两个内存的角色将两块空间的From和To名字互换完成垃圾的回收下次依然在From空间上创建对象。 如果内存中的垃圾对象较多需要复制的对象就较少这种情况下适合使用该方式并且效率比较高反之则不适合。 关键点总结 将内存区域分成两部分每次操作其中一个。 当进行垃圾回收时将正在使用的内存区域中的存活对象移动到未使用的内存区域。当移动完对这部分内存区域一次性清除。 周而复始。 核心流程演示 1.将堆内存分割成两块From空间 To空间对象分配阶段创建对象。 2.GC阶段开始将GC Root搬运到To空间 3.将GC Root关联的对象搬运到To空间 4.清理From空间并把名称互换 优点 吞吐量高复制算法只需要遍历一次存活对象复制到To空间即可比标记-整理算法少了一次遍历的过程因而性能较好但是不如标记-清除算法因为标记清除算法不需要进行对象的移动不会发生碎片化复制算法在复制之后就会将对象按顺序放入To空间中所以对象以外的区域都是可用空间不存在碎片化内存空间 缺点 内存使用效率低每次只能让一半的内存空间来为创建对象使用。 5.5 标记整理算法 标记整理算法也叫标记压缩算法是在标记清除算法的基础之上做了优化改进的算法。和标记清除算法一样也是从根节点开始对对象的引用进行标记在清理阶段并不是简单的直接清理可回收对象而是将存活对象都向内存另一端移动然后清理边界以外的垃圾从而解决了碎片化的问题。 核心思想分为两个阶段 标记阶段将所有存活的对象进行标记。Java中使用可达性分析算法从GC Root开始通过引用链遍历出所有存活对象。整理阶段将存活对象移动到堆的一端。清除存活边界以外的垃圾。 优点 内存使用效率高整个堆内存都可以使用不会像复制算法只能使用半个堆内存不会发生碎片化在整理阶段可以将对象往内存的一侧进行移动剩下的空间都是可以分配对象的有效空间 缺点 整理阶段的效率不高整理算法有很多种比如Lisp2整理算法需要对整个堆中的对象搜索3次整体性能不佳。可以通过Two-Finger、表格算法、ImmixGC等高效的整理算法优化此阶段的性能。 5.6 分代垃圾回收算法 现代优秀的垃圾回收算法会将上述描述的垃圾回收算法组合进行使用其中应用最广的就是分代垃圾回收算法(Generational GC)。 分代垃圾回收将整个内存区域划分为年轻代新生代和老年代【12】 对于新生代内部又被分为了三个区域。Eden区S0区S1区【811】 当对新生代产生GCMinorGC【young GC】 当对老年代代产生GCMajor GC 当对新生代和老年代产生FullGC 新生代 老年代完整垃圾回收暂停时间长应尽力避免。 我们通过arthas来验证下内存划分的情况 在JDK8中添加-XX:UseSerialGC参数使用分代回收的垃圾回收器运行程序。在arthas中使用memory命令查看内存显示出三个区域的内存情况。 Eden survivor 这两块区域组成了年轻代。 tenured_gen指的是晋升区域其实就是老年代。 另外还可以选择的虚拟机参数如下 含义参数堆初始大小-Xms堆最大大小-Xmx 或 -XX:MaxHeapSizesize新生代大小-Xmn 或 (-XX:NewSizesize -XX:MaxNewSizesize )幸存区比例动态-XX:InitialSurvivorRatioratio 和 -XX:UseAdaptiveSizePolicy幸存区比例-XX:SurvivorRatioratio晋升阈值-XX:MaxTenuringThresholdthreshold晋升详情-XX:PrintTenuringDistributionGC详情-XX:PrintGCDetails -verbose:gcFullGC 前 MinorGC-XX:ScavengeBeforeFullGC 代码 package chapter04.gc;import java.io.IOException; import java.util.ArrayList; import java.util.List;/*** 垃圾回收器案例1*/ //-XX:UseSerialGC -Xms60m -Xmn20m -Xmx60m -XX:SurvivorRatio3 -XX:PrintGCDetails public class GcDemo0 {public static void main(String[] args) throws IOException {ListObject list new ArrayList();int count 0;while (true){System.in.read();System.out.println(count);//每次添加1m的数据list.add(new byte[1024 * 1024 * 1]);}} }使用arthas的memory展示出来的效果 heap展示的是可用堆survivor区每次只有一块能使用所以60 - 4 56m。 工作机制 1、分代回收时新创建出来的对象首先会被放入Eden伊甸园区。 2、随着对象在Eden区越来越多如果Eden区满新创建的对象已经无法放入就会触发年轻代的GC称为Minor GC或者Young GC。 Minor GC会把需要eden中和From需要回收的对象回收把没有回收的对象放入To区采用复制算法复制完毕后伊甸园和 from 内存都得到释放。 3、接下来S0会变成To区S1变成From区。当eden区满时再往里放入对象依然会发生Minor GC。 此时会回收eden区和S1(from)中的对象并把eden和from区中剩余的对象放入S0。 注意每次Minor GC中都会为对象记录他的年龄初始值为0每次GC完加1。 4、如果Minor GC后对象的年龄达到阈值最大15默认值和垃圾回收器有关对象就会被晋升至老年代幸存区内存不足或大对象会导致提前晋升。 当老年代中空间不足无法放入新的对象时先尝试minor gc如果还是不足就会触发Full GCFull GC会对整个堆进行垃圾回收。 如果Full GC依然无法回收掉老年代的对象那么当对象继续放入老年代时就会抛出Out Of Memory异常。 下图中的程序为什么会出现OutOfMemory 从上图可以看到Full GC无法回收掉老年代的对象那么当对象继续放入老年代时就会抛出Out Of Memory异常。 继续使用这段代码测试 //-XX:UseSerialGC -Xms60m -Xmn20m -Xmx60m -XX:SurvivorRatio3 -XX:PrintGCDetails public class GcDemo0 {public static void main(String[] args) throws IOException {ListObject list new ArrayList();int count 0;while (true){System.in.read();System.out.println(count);//每次添加1m的数据list.add(new byte[1024 * 1024 * 1]);}} }结果如下 老年代已经满了而且垃圾回收无法回收掉对象如果还想往里面放就发生了OutOfMemoryError。 MinorGC、 Mixed GC 、 FullGC的区别是什么 MinorGC【young GC】发生在新生代的垃圾回收暂停时间短STW Mixed GC 新生代 老年代部分区域的垃圾回收G1 收集器特有 FullGC 新生代 老年代完整垃圾回收暂停时间长STW应尽力避免 名词解释 STWStop-The-World暂停所有应用程序线程等待垃圾回收的完成
http://www.zqtcl.cn/news/688142/

相关文章:

  • 北辰正方建设集团有限公司网站云南网站开发
  • 郑州网站建设信息前端用什么软件开发
  • 动漫视频网站开发做编程的网站有哪些方面
  • 做搜狗网站优化首页软外贸代运营
  • 巴士定制网站开发宁波快速制作网站
  • 永年区住房和城乡建设局网站网站后台文档
  • 网站备案授权书wordpress教程 页面
  • 深圳网站开发制作安徽全网优化
  • 陕西建设局网站appcms程序怎么做网站
  • 石家庄城乡建设厅网站牡丹江百度推广
  • 网站建设源代码 费用事件网站推广
  • 购物网站开发文献综述潮汕网站建设
  • 做五金生意什么网站做比较好网站建设市场规模
  • 网站跟app的区别是什么网络搭建结构图
  • 淘宝网站怎么做视频教程山西推广型网站开发
  • 杭州开发网站2018主流网站建设语言
  • 杂志社网站建设方案书响应式网站服务
  • 青岛网站开发建设农村建设有限公司网站
  • 做水晶接单在哪个网站接php做购物网站怎么样
  • 网站内部结构优化网页设计网站搭建
  • 杭州公司建设网站网络营销是一种什么营销
  • 事业单位网站建设费科目定西市小企业网站建设
  • 温州网站推广哪家好网站开发所遵循的
  • 没有网站做APP公司logo设计公司logo设计
  • 网站建设在哪个软件下做中国最大的现货交易平台
  • 西宁做网站公司电话加强局网站建设
  • 佛山做企业网站公司做贸易做个外贸网站有必要吗
  • 南昌制作网站的公司wordpress 分享到插件
  • 大型网站怎样做优化PHP站长工具怎么用
  • 响应式模板网站建设营销型网站建设怎么收费