#请讲一下JVM各代中垃圾确定和回收的算法
这里不得不先说一说 jvm的内存管理方式
java运行时数据区分为一下几个部分
- 方法区(线程私有)
这里存放的主要是类的信息
方法区里还包含常量池 主要存放一些与字节码一起初始化的变量 和一些字面量(这些字面量可以在任何时候产生 如string=“休闲鞋“的时候) 所以这里要注意方法区的溢出 (重点创建字面量的时候可以用StringBuilder) - 程序计数区(线程私有)
这里主要提供 类似计算机cup的pc寄存的的功能 这是jvm里唯一没有内存溢出问题的一个分区 - java虚拟机栈 (线程私有)
这里是提供java方法栈的语意(非native方法) 像汇编语言中的栈一样 维护方法中的局部变量 保存方法栈信息 保存现场 如果栈的深度过大 超出虚拟机容许的范围(当代虚拟机一般是自动适应大小的 但是还是有个栈限制)就会造成 栈溢出 如果不能分配更多的内存就会造成内存溢出 - 本地方法栈(线程私有)
本地方法栈主要是 native方法的栈 也有内存溢出 - java堆(线程共享 )堆里的对象都是由栈上的引用指向的
堆是java中最大的一片内存区域 主要存放一些实例对象和数组对象(java虚拟机规范中描述的是 :所有的对象实例遗迹数组都在堆上分配。但是随着jit 编译器的发展 逃逸分析技术逐渐成熟,栈上分配 ,标l量替换优化技术导致了微妙的变化 所有这么说也不是绝对的了)也可能给不同线程分配分配缓冲区 但是堆的地址空间是线程共享的 - 直接内存
直接分配内存 java nio里面利用直接分配内存 ,实现数据拷贝 ,减少数据从java堆中复制到native堆的过程 提高速度
###对象的创建
对象创建主要有两步 1在堆上创建实例对象 2 在栈上创建地址引用在堆上 创建对象分配内存主要有两种方法
1 指针碰撞 (主要适用于)
就是用过的内存 和空闲的内存进行区分 ,指针指向下一个空闲的内存 因此带有压缩功能的回收算法如serial ,parnew 就是采用指针碰撞算法进行寻找创建对象的地址
2 空闲列表
维护一个空闲区域的链表 分配的时候检索量表 这两种方法在操作系统课程中早已熟悉 主要回收算法 mark-sweep
对象的内存布局
对象在堆中主要分为3部分
- 对象头
主要存放对象的基本信息
有hashcode gc分代年龄 锁状态标志 线程私有锁 偏向线程id 偏向时间戳 一般32位虚拟机长度为32bit 64位 64bit 另外有可能存放指向类 的指针 - 实例数据
存放实例数据啦 - 对齐填充
就是内存对齐所需要的填充(有利于提高寻址速度) 参考汇编语言
##对象的访问定位
主要有两种方法
1 句柄(好像windows里这么称呼 *nux里称为啥 忘了 指针吧)
就是在堆里维护一张 类和实力地址的对应标 通过这张表去 查看类和 实例对应关系
2 直接指向
方法区直接指向对象实例 实例中记录所属类
好了 下面该说说 jvm内存回收算法了
主要有n种
1 引用技术算法
有个 引用计数器 引用数位0 则对象一死
2可达行分析
维护一颗树对象 所有对象都于gcroot节点项链 当不再与gcroot节点有联通性 说明对象已死
gc roots对象包含一下几种
1 虚拟机栈种引用的对象
2 方法区种的静态 属性引用对象
3 方法区种的常量引用对象
3 本地方法区种引用的对象
引用
引用分为4种
- 强引用
通过new创建的 只要强引用还在就不会被回收 - 软引用
当系统快要内存溢出的时候进行回收 如果回收后还不能分配足够的内存则被回收 - 如引用
垃圾回收时就被回收 - 虚引用
提供对象被回收器回收的时候的一个通知 这比判断null要好的多
回收方法区‘=
当一个常量被废弃
条件
该类的所有实例都已经被回收‘ 也就是java堆中不存在该类的任何实例
加载该类的classloader已经被回收
该类对应的java.lang.class对象哪有任何地方被引用 无法再任何地方反射引用该类
所以说 android里面的static 字段并不是可靠的 需要存储到文件中 是满足三个条件也不一定回收 要看虚拟机的设置
垃圾手机算法 有一下集中
1 标记清楚算法 mark-sweep
主要两个过程 标记-清除
2 复制算法
将对分成几块 ,将不死的对象复制到另一块 之前一块统统删除
这样实现 可以提高效率 但是浪费一点内存 再hotspoot虚拟机中默认一个eden区 两个survivor区
回收前讲一个survivor中的数据和eden中的数据拷贝到另一个 survivor中 清理这俩
默认eden和一个survivor比例为8:1 这样只浪费了10%的内存
3 标记-整理算法
当死亡对象比较少的时候复制算法复制过程降低效率 针对老年代是不合适的
标记整理针对老年代提出 就是标记过程和 标记清楚一样 回收的过程采用整理 而非复制 就是向一段整理
垃圾收集齐
1 serial收集器 单线程 历史最悠久 当收集的时候必须停止其他工作线程
2 parnew 收集器 多线程版的 serial 会停止工作线程
3 parallel scavenage 收集器
复制算法 减少停止用户线程的时间
4 serial old 收集器
5 parallel old 收集器
6cms收集器
标记清楚
初始标记
兵法标记
重新标记
并发清楚
分阶段 分线程