本文章分为4个部分介绍内存分配与回收,分别是内存是如何分配的,哪些内存需要回收,什么情况下执行回收,如何监控和优化GC垃圾回收机制。
JavaGC(Garbage Collection)垃圾回收机制,是Java的和C、C++的主要区别。通过对JVM内存进行标记,自主回收一些无用的内存。
1、Java内存区域
在Java运行时数据区里,由jvm管理内存区域分为多个部分
![2b8c54528952afa633e57287ee790ec2.png](https://i-blog.csdnimg.cn/blog_migrate/a458035d3adf02b6bd7fd47762caaaf2.jpeg)
程序计数器:是一个比较的内存单元,用来表示当前程序运行哪里的一个指示器。由于每个线程都有自己的执行顺序,所以程序计数器是线程私有的,每个线程都要有一个自己的程序计数器来指示自己下一步要执行的指令。
虚拟机栈:当线程的每个方法在执行的时候都会创建一个栈帧用来存储方法中的局部变量,方法出口等,同时会将这个栈帧放入JVM栈中,方法调用完成时,这个栈帧出栈。每个线程都要有一个自己的虚拟机栈来保存自己的方法调用时候的数据,因此虚拟机栈也是线程私有的。
虚拟机栈中定义了两种异常,如果线程调用的栈深度大于虚拟机允许的最大深度,抛出StackOverFlowError,不过虚拟机基本上都允许动态扩展虚拟机栈的大小。这样的话线程可以一直申请栈,直到内存不足的时候,会抛出OOME内存溢出。
本地方法栈:本地方法栈与虚拟机栈类似,只是本地方法栈存放的栈帧是在native方法调用的时候产生的。有的虚拟机中会将本地方法栈和虚拟机栈放在一起,因此本地方法栈也是线程私有的。
方法区:又叫做静态区,用于存储类的信息,常量池等,逻辑上是堆的一部分,是各个线程共享的区域,为了与堆区分,又叫非堆。在永久代还存在时,方法区被用作永久代。方法区可以选择是否开启垃圾回收。
直接内存:直接内存指的是非jvm管理的内存,是机器剩余的内存。用基本通道(channel)和缓冲区(buffer)的方式进行内存分配,用存储在JVM中的DirectByteBuffer来引用,当机器本身内存不足时,会抛出OOME
举例来说明:Object obj = new Object()
obj表示一个本地引用,存储在jvm栈的本地变量中,new Object()作为一个对象放在堆中,Object类的类型信息放在堆中,而这些类型信息的地址放在方法区中。
这里需要知道如何通过引用访问到具体对象,也就是通过obj引用如何找到new出来的这个Object对象,主要有两种方法,通过句柄和通过直接指针来访问。
![be2edfb725567338c68a25a1c082971a.png](https://i-blog.csdnimg.cn/blog_migrate/6b593df580f68f0e1cd76766490d1343.jpeg)
在Java堆中会专门有一个区域被划分为句柄池,一个引用的背后是一个对象实例数据的指针和对象类型信息的指针,而这两个指针都在Java堆上的。这种方法是优势较为稳定,但是速度不是很快。
![945891eaf2d1583820f08ca25e0b5d4f.png](https://i-blog.csdnimg.cn/blog_migrate/cc9f5f6440a5bca2e89ee6a8e9c0f293.jpeg)
一个引用背后是一个对象的实例数据,这个实例数据里面包含了“到对象类型信息的指针”。这种方式的优势是速度快,在HotSpot中用的就是这种方式。
2、内存是如何分配和回收的
内存分配主要是在堆上的分配,如前面new出来的对象,放在堆上,但是现代技术也支持在栈上分配。
jvm中将对象根据存活的时间分为三代:年轻代、年老代和永久代。在jDK 1.8中已经不再使用永久代。
![7161fe187f67bc85078393f83be980ea.png](https://i-blog.csdnimg.cn/blog_migrate/96d7417e7007168cabc24b8e143eff39.jpeg)
年轻代:又叫新生代,所有新生代的对象都是先放在年轻代。年轻代分为三个区,一个Eden区,两个Survivor区,一个叫From,一个叫To,当Eden中满时,执行Minor GC将消亡的对象清理掉,仍存活的对象将被复制到Survivor中的From区,清空Eden.当这个From区满的时候,仍存活的对象将被复制到To区,清空From区,并将原From区变为To区,原To区变为From区,这样的目的是保证To区一直为空。当From区满无对象可清理或者From-To区交换的次数超过设定的时候,仍存活的对象进入老年代。年轻代中Eden和Survivor的比例通过-XX: SURivorRation参数来配置,默认为8,也就是说Eden:From:To = 8:1:1.年轻代的回收方式叫做Minor GC,又叫停止-复制清理法。
年老代:年老代的空间较大,当年老代内存不足时,将执行Major GC也叫Full GC.如果对象比较大,可能会直接分配到老年代而不经过年轻代。用-XX:pertenureSizeThreashold来设定这个值,大于这个的对象会直接分配到老年代上。
3、垃圾收集器
在GC机制中,起作用的是垃圾收集器。
JavaGC是一个非常复杂的机制,想要详细说清楚可以给我点时间。转发加关注,以后有更好的文章分享。
![6ad01402d33857fbb2ed02437015aa36.png](https://i-blog.csdnimg.cn/blog_migrate/ef05a2ff5be7b1b926f0ac24589d2fd9.jpeg)