JVM-GC-什么是垃圾
前言
所谓垃圾其实是指,内存中没用的数据;没有任何引用指向这块内存,或者没有任何指针指向这块内存。没有的数据应该被清除,垃圾的处理其实是内存管理问题。
JVM虽然不直接遵循冯诺依曼计算机体系架构,但极其相似,像是一台小型计算机。
一台计算机运行程序的流程大概是这样的:操作系统先将程序加载(load)至内存中,并产生一个进程;CPU在内存中读取指令集并执行;在CPU执行期间需要用到内存中的数据,因此在CPU执行期间内存是必须的;
JVM是执行时,是通过不停的压栈弹栈执行指令的,如果需要内存中数据的时候是通过将引用地址压栈到内存中来获取内存中数据的。栈空间是线程独享,而堆空间是线程不独享的。栈空间在弹栈后释放,而堆空间不会;因此JVM存在内存管理的问题。
内存管理常见问题
内存泄露与内存溢出
内存泄露是指,内存中的数据没有任何引用或者说没有任何指针指向该空间,即垃圾数据;
内存溢出是指内存空间不够,程序无法运行,当内存泄露过多后就会导致内存溢出;
野指针
野指针是指指针指向位置的数据被其他线程释放了,甚至是被其他线程重新占用,导致指针指向的位置是一个不确定的变量;
不同语言的内存管理
- c/c++是通过手动方式管理内存的,如C中的free()函数,C++中的delete函数。极其难管理,很容以出现内存泄露、野指针等问题;
- java/Python/Golang等后来是通过垃圾回收器自动回收垃圾,再也不需要程序员来手动管理内存。
- 还有一些语言是不需要手动管理内存也不需要GC,如rust,它是通过一个内存空间只能一个引用的方式实现的。
手动管理内存的语言麻烦且容易出问题,但线程全部用来执行业务;而使用GC的语言,不需要考虑内存管理的问题,但是需要消耗线程来处理垃圾,效率低;
寻找垃圾的方式
- reference count(引用计数法):即通过记录引用的数量或指针的数量来判断是否为垃圾,但是会出现循环引用,导致内存泄露;
- root searching: 根可达寻找,从引用的头开始遍历,没有被遍历到的数据为垃圾,JVM中根的定义:
- 线程变量
- 静态变量
- 常量池变量
- JNI指针
清除垃圾的方式
- mark-sweep:标记清除,弊端是内存碎片化严重
- copying:拷贝清除,只占用一半的内存空间,将没有没清除的数据copy到另外一般内存中。弊端是内存地址发生变化,占用内存
- mark-compact:标记压缩,在情况垃圾的同时将内存整理。弊端占用CPU