在默认情况下,System.gc()或者Runtime.getRuntime().gc()的调用,会显式触发Full GC,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存。
其附带免责声明,无法保证对垃圾收集器的调用。
{
byte[] buffer = new byte[10*1024*1024];
}
int value = 10;//只写代码块时不会回收,当定义了之后才会占用空间,才会进行回收(SLot 复用)。
System.gc();
2 内存溢出和内存泄漏
内存溢出:没有空闲内存,并且垃圾收集器也无法提供更多内存。
原因:
1)java虚拟机的堆内存设置不够
2)代码中创建大量大对象,并且长时间不能被垃圾回收器所回收(存在被引用)。
内存泄漏:
严格来说,只有对象不会再被程序用到了,但是GC又不能回收他们的情况,才叫内存泄漏。
但实际上很多时候一些不太好的实践会导致对象的声明周期变得很长甚至导致OOM,也可以叫做广泛意义上的”内存泄漏“。
尽管内存泄漏并不会立刻引起程序崩溃,但是一旦发生内存泄漏,程序中的可用内存就会被逐步蚕食,直到耗尽所有内存,最终出现oom异常导致程序崩溃。
例子:1.定义变量的时候定义为了静态变量(本来可用定义为成员变量)。
举例:
1)单例模式
单例的生命周期和应用程序一样长,所有单例程序中,如果持有外部对象的引用的话,那么这个外部对象是不能被回收的,则导致内存泄漏的产生。
2)一些提供close的资源未关闭导致内存泄漏。数据库连接,网络连接和io连接必须手动close,否则是不能被回收的。
3 Stop The Word
简称STW,指的是GC事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应,有点像卡死的感觉,这个停顿称为STW。
STW和采取哪款GC无关,所有的GC都有这个事件,哪怕时G1也不能完全避免Stop-the-world情况的发生,只能说垃圾回收器越来越优秀,回收效率越来越高,尽可能地缩短了暂停时间。
STW是JVM在后台自动发起和自动完成的。在用户不可见的情况下,把用户正常的工作线程全部停掉。
开发中不要用System.gc(),这会导致stop-the-world的发生
4 垃圾回收的并行和并发
并行:指多条垃圾收集线程并行工作,但此时用户线程依旧处于等待状态
串行:相较于并行概念,单线程执行。如果内存不够,则程序暂停,启动垃圾回收器进行垃圾回收,回收完再启动程序的线程。
并发:指用户线程和垃圾回收线程同时执行(但不一定是并行的,可能会交替执行),垃圾回收线程在执行时不会停顿用户程序的执行。
5 安全点和安全区域
程序执行时并非在所有的地方都能停顿下来开始GC,只有在特定的位置才能停顿下来开始GC,这些位置称为安全点。选择标准会根据”是否具有让程序长时间执行的特征“,比如方法调用、循环跳转和异常跳转等。
如何在发生GC时,检查所有线程都跑到最近的安全点停顿下来?
1)抢占式中断:首先中断所有线程,如果还有线程不在安全点,就恢复线程,让线程跑到安全点。(目前没有虚拟机采用)
2)主动式中断:设置一个中断标志,各个线程运行到Safe Point的时候主动轮询这个标志,如果中断标志为真,则将自己进行中断挂起。
安全区域:安全区域指的时一段代码片段中,对象的引用关系不会发生变化,在这个区域的任何位置开始GC都是安全的。
实际运行时:
1)当线程运行到safe region的代码时,首先标志已经进入safe region,如果这段时间内发生GC,JVM会忽略标识为safe region状态的线程。
2)当线程即将离开safe region时,会检查JVM是否已经完成GC,如果完成了,则继续运行,否则线程必须等待直到可可以安全离开safe region。
6 强引用
最传统的”引用“的定义,是指在程序代码之中普遍存在的引用赋值,即类似”object obj = new object()“这种引用关系,只要强引用关系还在,垃圾收集器就永远不会回收掉被引用的对象。可以直接访问目标对象。
最常见的引用类型(普通系统99%以上都是强引用),也就是我们最常见的普通对象引用,也是默认的引用类型。强引用的对象是可触及的,就永远不会回收掉被引用的对象,强引用也是造成java内存泄漏的主要原因之一。
7 软引用
软引用是用来描述一些还有用,但是非必须的对象。制备软引用关联的对象,在系统将要发生内存溢出异常前,会把这些对象列进回收范围之中进行第二次回收。
软引用通常用于实现敏感的缓存。比如:告诉缓存就有用到软引用。如果华友空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时不会耗尽内存。
8 弱引用
只被弱引用关联的对象发现即回收。
WeakHashMap:继承自weakReference
9 虚引用
一个对象是否有虚引用的存在,完全不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它和没有引用几乎完全一样,随之都可能被垃圾回收器回收。它不能单独使用,必须提供一个引用队列,也不能通过虚引用用来获取被引用的对象。当试图通过虚引用的get方法获取对象的时候,总是null。
为一个对象设置虚引用关联的唯一目的在于跟踪垃圾回收过程:比如在对象被垃圾回收的时候收到一个系统通知。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象后,将这个虚引用加入引用队列,以通知应用程序对象的回收情况。
10 终结器引用
1)用于实现对象的finalize()方法,也可以称为终结器引用
2)无需手动编码,其内部配合队列使用。