垃圾回收机制算法(GC)
必问问题:什么是垃圾回收机制?
答:就是不定时的去堆内存清理不可达对象(可达:对象经常使用,只要被引用)。
在C语言中,对象是要手动清理的,在java中有一个gc线程,会不定时的去清理不可达对象。
注释:调用了gc()手动回收,也只是有大概率会执行finalize()回收前的方法,
内存溢出和内存泄露的区别
内存泄漏的定义:对象已经没有被应用程序使用,但是垃圾回收器没办法移除它们,因为还在被引用着。
内存溢出的定义:项目需要4G,但是运行环境只支持3G,溢出。
如何防止内存泄露
下面是几条容易上手的建议,来帮助你防止内存泄漏的发生。
· 特别注意一些像HashMap、ArrayList的集合对象,它们经常会引发内存泄漏。当它们被声明为static时,它们的生命周期就会和应用程序一样长。
· 特别注意事件监听和回调函数。当一个监听器在使用的时候被注册,但不再使用之后却未被反注册。
· 如果一个类自己管理内存,通常一些成员变量引用其他对象,初始化的时候需要置空。
引用计数法(新生代)
每个对象在堆内存eden都有有一个标记默认15次机会,gc回收,如果对象没有继续使用就-1,继续使用就+1,0次的时候gc直接回收,如果15次的时候+1就会进入s0和s1,在继续使用就进入老年代。
优点:
引用计数收集器可以很快的执行,交织在程序运行中。对程序需要不被长时间打断的实时环境比较有利。
缺点:
无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为0.而且每次加减非常浪费内存。
复制算法(新生代 s0 s1大小相等)
连续性,不会产生碎片化,就是没有残留。
每个对象在堆内存中通过引用计数法后若超过15次之后就会先存入s0区,此时若有另一个对象加入,也会存到当前存在有对象的区里,当gc回收的时候,若发现其中有不可达的对象 的时候,现将其他的对象复制到另一个空的区里,再讲不可达的对象直接抹掉回收掉,以此类推。
这样使得每次都是对其中一块内存进行回收,内存分配时不用考虑内存碎片等复杂情况,只需要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。
复制算法的缺点显而易见,可使用的内存降为原来一半。
标记清除(老年代)
每一个对象都做一个标记,0是可达,1是不可达。当对象不经常使用了,就标记为1,
缺点:不连续,有残留
标记压缩(老年代)
保留了标记清除的本质,但是把不可达的放在一起,连续回收,没有残留
分带收集算法
区分老年代和新生代分别进行回收机制。
垃圾回收机制如果频繁执行会降低效率?
垃圾回收的任务是识别和回收垃圾对象进行内存清理,为了让垃圾回收器可以更高效的执行,大部分情况下,会要求系统进如一个停顿的状态。停顿的目的是为了终止所有的应用线程,只有这样的系统才不会有新垃圾的产生。同时停顿保证了系统状态在某一个瞬间的一致性,也有利于更好的标记垃圾对象。因此在垃圾回收时,都会产生应用程序的停顿。
垃圾收集器
什么是垃圾收集器
Java垃圾回收器是Java虚拟机(JVM)的三个重要模块(另外两个是解释器和多线程机制)之一,为应用程序提供内存的自动分配(Memory Allocation)、自动回收(Garbage Collect)功能,这两个操作都发生在Java堆上(一段内存快)。某一个时点,一个对象如果有一个以上的引用(Rreference)指向它,那么该对象就为活着的(Live),否则死亡(Dead),视为垃圾,可被垃圾回收器回收再利用。垃圾回收操作需要消耗CPU、线程、时间等资源,所以容易理解的是垃圾回收操作不是实时的发生(对象死亡马上释放),当内存消耗完或者是达到某一个指标(Threshold,使用内存占总内存的比列,比如0.75)时,触发垃圾回收操作。有一个对象死亡的例外,java.lang.Thread类型的对象即使没有引用,只要线程还在运行,就不会被回收。
串行收集器:回收期间暂停所有应用线程的执行,client模式下的默认回收器,通过-XX:+UseSerialGC命令行可选项强制指定。参数可以设置使用新生代串行和老年代串行回收器
并行收集器:并行回收器在串行回收器基础上做了改进,他可以使用多个线程同时进行垃圾回收,对于计算能力强的计算机而言,可以有效的缩短垃圾回收所需的实际 时间。
-XX:+UseParallelOldGC 进行设置
-XX:+ParallelCThread也可以设置垃圾收集时的线程教量。
吞吐量:请求成功多少次/s
Tomcat调优总结
初始堆值和最大堆内存内存越大,吞吐量就越高。
最好使用并行收集器,因为并行收集器速度比串行吞吐量高,速度快。
设置堆内存新生代的比例和老年代的比例最好为1:2或者1:3。
减少GC对老年代的回收。