GarBageCollection
首先说一下java的gc垃圾回收机制,到底什么时候回收,在哪里回收。
经常说java分别在栈区和堆区存储变量等。其实还有
程序计数器
它是一个字节码的指示器,告诉当前线程下一步要执行哪一行代码。一个没有OOm的区域
栈区
又叫java虚拟机栈区,是每一个方法被执行的时候,创建出一个栈帧用来放的成员变量,操作链表,动态链接,方法出口。很多个栈帧又存储在栈区。
本地方法栈
如果说栈区是一个java的本地方法栈,那么本地方法栈就就是c++的native栈区
堆区
当类中创建实例变量,就会在堆区中分配内存,堆区又分为新生代,老年代。当新生代没有足够多内存实例对象就是OOM
方法区
用来存放被虚拟机加载的类信息,常量,静态变量。
运行时常量池
运行时常量池用来存放编译期间的常量
什么时候GC
- 在类中每当我们实例化一个变量时,都会在新生区申请足够的内存,如果申请的内存不足以实例化对象,这时候就会minor GC 小规模的回收。
- 在太多的对象在老年代,导致没有足够的内存空间加入对象时,就会full GC,并且直到老年代能放得下更大的对象。
- 每次minor gc都会检查一下进入老年代的对象和老年代剩余空间,如果不够就会full gc
- 手动执行System.gc();
内存碎片
内部碎片
分配内存到进程A,内存被进程占据了而不被利用,同时系统也无法利用这块内存,直到进程A被终结,释放内存。
外部碎片
还没被分配出去的内存太少了不足分配给下一个进程,又或者多个不连续的内存总空间长度能满足新申请的进程,但是由于地址是不连续的内存,无法分配给新进程。
Java硬软弱虚引用
硬引用
硬引用是我们用得最普遍的方式,就算应用程序内存不足,需要的内存大于可用的内存发生OOM程序崩溃,也不会去回收这个对象。
软引用
当内存足够就不会去回收这个对象,当内存不够就会去回收这个对象把引用对象加入SoftReference对象,把引用赋值成null,手动调用System.gc(),加不加入ReferenceQueue队列取决于内存够不够用。回收对象都会进入ReferenceQueue。
ReferenceQueue<Object> queue=new ReferenceQueue<Object>();
Object object =new Object();
SoftReference<Object> softReference=new SoftReference<>(object,queue);
obj=null;
System.gc();
System.out.println(queue.poll());//查看队列元素
弱引用
当回收器扫描出弱引用不管内存是否够用,都会回收这个对象。把弱引用对象加入WeakReference对象,把引用赋值成null,手动调用System.gc(),到最后的才会加入ReferenceQueue队列。回收对象都会进入ReferenceQueue。
ReferenceQueue<Object> queue=new ReferenceQueue<Object>();
Object object =new Object();
WeakReference<Object> softReference=new WeakReference<>(object,queue);
obj=null;
System.gc();
System.out.println(queue.poll());//查看队列元素
虚引用
当GC发现了虚引用对象把对象加到PhantomReference对象中,最后将虚引用赋值为null,再手动调用System.gc(),到最后的才会加入ReferenceQueue队列。回收对象都会进入ReferenceQueue。
ReferenceQueue<Object> queue=new ReferenceQueue<Object>();
Object object =new Object();
PhantomReference<Object> softReference=new PhantomReference<>(object,queue);
obj=null;
System.gc();
System.out.println(queue.poll());//查看队列元素