Garbage Collection : 垃圾收集,简称GC
在使用java的时候,我们将内存交由虚拟机管理,而不需开发人员过度关注,但并不意味着我们可以不学习什么是垃圾回收和内存分配。因为当需要排查各种内存溢出、内存泄漏问题时,垃圾回收成为系统达到更高并发量的瓶颈时(gc需要占用工作线程),我们需要能进行监控和调节。
Java的内存运行区数据中,程序计数器、虚拟机栈、本地方法栈这3个区域随线程而生亡,其栈帧分配多少内存基本上是在类结构确定下来时就已知的,所以这3个区域的内存分配和回收都具备确定性,而不需要关注如何回收:当方法结束或者线程结束时,内存自然就回收了
那么哪个区域的内存需要考虑呢:java堆和方法区
比如:一个接口的多个实现类需要的内存可能不同,一个方法所执行的不同条件分支所需要的内存也可能不一样,只有在运行期才能知道创建哪些对象,创建多少个对象。这部分内存的分配和回收是动态的,我们将讨论java这部分内存的分配和回收
如果让你设计垃圾回收,可以有哪些方法
引用计数算法
在使用c++的智能指针share_ptr时,其采用一个计数器来记录对象的引用情况,当新增引用时,计数器+1,引用失效时,计数器就-1.当计数器值为0时,对象可以被自动化释放。
采用引用计数算法比较简单,但随着的问题在于解决循环引用的问题,而在Java中,大多数的JVM并没有选用引用计数算法,主要在于JVM整体不像c++的share_ptr这样简化。
可达性分析算法
这个算法的思路是通过一系列称为"GC Roots"的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为“引用链”(Reference Chain),如果某个对象到GC Roots间没有任何引用链相连,或者用图论的话来说就是从GC Roots到这个对象不可达时,则表明该对象不可能再被使用。
在Java体系中,固定可作为GC Roots对象包括以下几种:
1、在虚拟机栈(栈帧中的本地变量表)中引用的对象
2、在方法区中类静态属性引用的对象
3、在方法区中常量引用的对象
4、在本地方法栈中JNI(Native方法)引用的对象
5、Java虚拟机内部的引用
6、所有被同步锁(synchronized)持有的对象
7、反映JVM内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等
了解哪些是GC Roots对象,我们再回头看什么是引用?哎?引用不就是 数据中存储的数值代表的另外一块内存的起始地址么?这有啥好解释的?
Java 引用
强引用(Strongly Reference):程序中普遍存在的引用