1.为什么虚拟机需要垃圾处理器、
首先我们要知道垃圾处理器的作用:
- 哪些内存需要回收
- 什么时候进行回收
- 通过什么方式进行回收。总所周知,运行的时候都是单线程,那我们如何在用户进程和垃圾回收进程之间进行切换。
如今的内存分配技术和内存回收技术已经相当的成熟了,为什么我们还要去了解垃圾收集和内存分配呢?
这与我们排查各种内存泄露、内存溢出问题的时候有关,当垃圾处理器称为了系统持续发展的瓶颈的时候,就需要我们对这些技术进行监控和调节。
1.1.关于上文内存溢出和内存泄露的讲解
所谓的内存溢出:指的是程序运行过程中无法申请到足够的内存而导致的一种错误。内存溢出一般发生于OLD段和Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况
而内存泄露是指程序中动态分配内存给一些临时的对象,但是对象不会被GC所回收,它始终占用内存。简单来说就是,被分配对象可达但是无用。
1.2.垃圾处理器的对对象是否存在的判断
目前看来似乎就只有引用计数算法和可达性分析法
主流的Java虚拟机里面没有选用引用计数法来管理内存,其一是因为需要配合大额外 处理才能保证正确地工作,例如其对象相互循环引用的问题
引用计数算法的基本思路:引用计数算法很简单,它实际上是通过在对象头中分配一个空间来保存该对象被引用的次数。如果该对象被其它对象引用,则它的引用计数加一,如果删除对该对象的引用,那么它的引用计数就减一,当该对象的引用计数为0时,那么该对象就会被回收。
可达性算法的基本思路:通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索的过程所走过的路劲被称为“引用链”,如果对象到GC Roots间没有任何引用链相连,或者就是从起始节点集到这个对象不可达时,证明该对象是不可能再被引用。然后他们会被判断为可回收对象。
在Java的技术体系中,被判定为可作为GC Roots的对象包括以下几种:
1.虚拟机栈(栈帧中的本地变量表)中引用的对象。各个线程被调用的方法堆、栈中所使用到的参数、局部变量。
2.在方法区中类静态属性引用的对象。Java类的引用类型静态变量。
3.在方法区常量引用的对象
4.在本地方法栈中JNI引用的对象
5.所有被同步锁持有的对象
6.反应Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等
1.3.引用
JDK1.2版本之后,Java对引用分为了强引用、软引用、弱引用、虚引用。
- 强引用是代码中最传统的引用定义
- 软引用来描述一些还有用,但是非必须的对象
- 弱引用也是来描述那些非必须的对象,比软引用更弱一些
- 虚引用,为对象设置虚引用关联的唯一目的只是为了能够在这个对象被收集器回收时收到一个临时通知
1.4.是否被回收
在可达性算法中判断为不可达的对象,并不是一定要进行回收的。
一个对象至少要经历两次的标价过程:当发现该对象没有与起始节点集相连接的引用链,它会被第一次标记。
接着一次筛选是finalize()方法,该对象是否有必要执行该方法。
1.5.回收方法区
方法区的垃圾收集主要回收两部分内容:废弃的常量和不再使用的类型
后者相对于前者来说是更困难的,需要满足下面三个条件
1.所有类的实例都已经被回收
2.加载该类的类加载器已经被会说
3.该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方访问该类