Moosphan/Android-Daily-Interview

2019-09-05:请谈谈Java的内存回收机制?

Moosphan opened this issue · 8 comments

2019-09-05:请谈谈Java的内存回收机制?

这个不好回答,当时候我被问到过

该回收的就回收了,如果该回收的没回收,说明出现了bug,还有优化空间

在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方面工作都是由JVM自动完成的,降低了Java程序员的学习难度,避免了像C/C++直接操作内存的危险。但是,也正因为内存管理完全由JVM负责。

这个比较麻烦,可以看下我的博客

Java回收机制

引用计数法,可达性分析。
垃圾回收方法有:标记-清除,复制,新生代老生代,标记-移动

一图胜千言

那我就来说说 java的 分代回收机制吧
java中的内存分配 主要有 新生代 老年代两种
新生代有 eden 和两个survivor区 from 和 to
eden 和survivor比例是 8:1:1
每次 分配对象 都会先去eden区 满了就会发生gc 就到survivor from 区, 再不够就去老年代
通常大对象是直接去老年代的,老年代的空间是新生代的2倍

发生gc 又分为两种 minor gc, 只发生在新生代, 会把可达对象从 eden 和from 区复制到 to区,
如果不够 还会进入老年代, 然后把 eden 和from 清空, 把 to区当做from区.

老年代gc 又叫做 major gc 通常不太会发生 并且发生的时间是 minor的十倍.

基础

内存分为栈(stack)和堆(heap)两部分:

  • 栈记录了方法调用,每个线程拥有一个栈,栈的每一帧中保存有该方法调用的参数、局部变量、返回地址

  • 栈中被调用方法运行结束时,相应的帧会删除,参数和局部变量占用的空间也会释放

  • 堆是用来存储对象的,堆区由所有线程共享

定义

垃圾回收指的是:JVM自动清空堆中无用的对象占用的空间的过程

垃圾回收机制

有:引用计数算法、可达性分析算法、标记清除算法、复制算法、标记整理算法、分代回收算法。

a、引用计数算法中,每个对象包含一个计数器,有新的引用指向该对象时计数器加1,引用移除时计数器减1,计数器为0时回收对象,引用计数法有个缺陷是无法检测出循环引用。

b、可达性分析算法中,每个对象都有一个用于标示该对象是否可到达的标记信息。从根出发跟随所有的引用,就可以找到所有的可到达对象,不可到达对象就是需要垃圾回收的对象。

c、标记清除算法流程为,垃圾回收启动时,Java程序暂停运行,JVM从根出发找到所有的可达对象并标记,然后扫描整个堆找到不可达对象并清空。缺点是标记、清除的效率不高;会产生内存碎片。

d、复制算法为,将内存分为大小相等的两块,每次使用一块,使用完时将存活的对象复制到另一块,清空原来那块。在对象存活率较低时回收效率高,缺点是内存空间使用率只有一半。

e、标记整理算法下,找到所有的可达对象并标记后,将所有存活对象都向内存区域的一端移动,然后清理掉边界以外的内存区域。

f-1、分代回收算法下,堆分为三代:永久代、老年代、新生代,新生代又分为三个区域:eden区、from区和to区。

f-2、永久世代主要存放静态文件如Java静态类、方法等,对于垃圾回收没有显著影响。

f-3、分代回收流程为,上次垃圾回收后创建的对象叫新生对象,存放于eden区,eden区没有空间存放新生对象时,触发一次MinorGC,采用标记整理算法将eden区和from区的可达对象复制到to区,清空eden区和from区空间,此时from区和to区已交换;当to区也放不下eden和from区的可达对象时,将部分对象放到成熟世代;当成熟世代也已满时触发MajorGC,采用标记清除算法进行垃圾回收。

f-4、其中,即使to区没有满,JVM也会移动生命周期足够久远的对象到成熟世代;MinorGC发送频率较高,MajorGC发生频率较低。